diff --git a/.clang-format b/.clang-format index c4f7dfc34..f4a05d79e 100644 --- a/.clang-format +++ b/.clang-format @@ -57,7 +57,7 @@ SpacesInCStyleCastParentheses: 'false' SpacesInContainerLiterals: 'true' SpacesInParentheses: 'false' SpacesInSquareBrackets: 'false' -UseTab: ForIndentation +UseTab: 'false' --- Language: Cpp diff --git a/core/AES.cpp b/core/AES.cpp index 038a62d7f..07648489f 100644 --- a/core/AES.cpp +++ b/core/AES.cpp @@ -11,9 +11,10 @@ */ /****/ -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" + #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif @@ -31,660 +32,775 @@ namespace ZeroTier { namespace { -#define s_bmul32(N, x, y, rh, rl) \ - uint32_t x0t_##N = (x) & 0x11111111U; \ - uint32_t x1t_##N = (x) & 0x22222222U; \ - uint32_t x2t_##N = (x) & 0x44444444U; \ - uint32_t x3t_##N = (x) & 0x88888888U; \ - uint32_t y0t_##N = (y) & 0x11111111U; \ - uint32_t y1t_##N = (y) & 0x22222222U; \ - uint32_t y2t_##N = (y) & 0x44444444U; \ - uint32_t y3t_##N = (y) & 0x88888888U; \ - uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \ - uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \ - uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \ - z0t_##N |= z1t_##N; \ - z2t_##N |= z0t_##N; \ - uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \ - (rh) = (uint32_t)(zt_##N >> 32U); \ - (rl) = (uint32_t)zt_##N; +#define s_bmul32(N, x, y, rh, rl) \ + uint32_t x0t_##N = (x)&0x11111111U; \ + uint32_t x1t_##N = (x)&0x22222222U; \ + uint32_t x2t_##N = (x)&0x44444444U; \ + uint32_t x3t_##N = (x)&0x88888888U; \ + uint32_t y0t_##N = (y)&0x11111111U; \ + uint32_t y1t_##N = (y)&0x22222222U; \ + uint32_t y2t_##N = (y)&0x44444444U; \ + uint32_t y3t_##N = (y)&0x88888888U; \ + uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) \ + ^ ((uint64_t)x3t_##N * y1t_##N)) \ + & 0x1111111111111111ULL; \ + uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) \ + ^ ((uint64_t)x3t_##N * y2t_##N)) \ + & 0x2222222222222222ULL; \ + uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) \ + ^ ((uint64_t)x3t_##N * y3t_##N)) \ + & 0x4444444444444444ULL; \ + z0t_##N |= z1t_##N; \ + z2t_##N |= z0t_##N; \ + uint64_t zt_##N = z2t_##N \ + | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) \ + ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) \ + & 0x8888888888888888ULL); \ + (rh) = (uint32_t)(zt_##N >> 32U); \ + (rl) = (uint32_t)zt_##N; -void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept +void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept { - uint32_t hhh = (uint32_t)(hh >> 32U); - uint32_t hhl = (uint32_t)hh; - uint32_t hlh = (uint32_t)(hl >> 32U); - uint32_t hll = (uint32_t)hl; - uint32_t hhXlh = hhh ^hlh; - uint32_t hhXll = hhl ^hll; - uint64_t yl = Utils::ntoh(y0); - uint64_t yh = Utils::ntoh(y1); - uint32_t cilh = (uint32_t)(yh >> 32U); - uint32_t cill = (uint32_t)yh; - uint32_t cihh = (uint32_t)(yl >> 32U); - uint32_t cihl = (uint32_t)yl; - uint32_t cihXlh = cihh ^cilh; - uint32_t cihXll = cihl ^cill; - uint32_t aah, aal, abh, abl, ach, acl; - s_bmul32(M0, cihh, hhh, aah, aal); - s_bmul32(M1, cihl, hhl, abh, abl); - s_bmul32(M2, cihh ^ cihl, hhh ^ hhl, ach, acl); - ach ^= aah ^ abh; - acl ^= aal ^ abl; - aal ^= ach; - abh ^= acl; - uint32_t bah, bal, bbh, bbl, bch, bcl; - s_bmul32(M3, cilh, hlh, bah, bal); - s_bmul32(M4, cill, hll, bbh, bbl); - s_bmul32(M5, cilh ^ cill, hlh ^ hll, bch, bcl); - bch ^= bah ^ bbh; - bcl ^= bal ^ bbl; - bal ^= bch; - bbh ^= bcl; - uint32_t cah, cal, cbh, cbl, cch, ccl; - s_bmul32(M6, cihXlh, hhXlh, cah, cal); - s_bmul32(M7, cihXll, hhXll, cbh, cbl); - s_bmul32(M8, cihXlh ^ cihXll, hhXlh ^ hhXll, cch, ccl); - cch ^= cah ^ cbh; - ccl ^= cal ^ cbl; - cal ^= cch; - cbh ^= ccl; - cah ^= bah ^ aah; - cal ^= bal ^ aal; - cbh ^= bbh ^ abh; - cbl ^= bbl ^ abl; - uint64_t zhh = ((uint64_t)aah << 32U) | aal; - uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal); - uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl); - uint64_t zll = ((uint64_t)bbh << 32U) | bbl; - zhh = zhh << 1U | zhl >> 63U; - zhl = zhl << 1U | zlh >> 63U; - zlh = zlh << 1U | zll >> 63U; - zll <<= 1U; - zlh ^= (zll << 63U) ^ (zll << 62U) ^ (zll << 57U); - zhh ^= zlh ^ (zlh >> 1U) ^ (zlh >> 2U) ^ (zlh >> 7U); - zhl ^= zll ^ (zll >> 1U) ^ (zll >> 2U) ^ (zll >> 7U) ^ (zlh << 63U) ^ (zlh << 62U) ^ (zlh << 57U); - y0 = Utils::hton(zhh); - y1 = Utils::hton(zhl); + uint32_t hhh = (uint32_t)(hh >> 32U); + uint32_t hhl = (uint32_t)hh; + uint32_t hlh = (uint32_t)(hl >> 32U); + uint32_t hll = (uint32_t)hl; + uint32_t hhXlh = hhh ^ hlh; + uint32_t hhXll = hhl ^ hll; + uint64_t yl = Utils::ntoh(y0); + uint64_t yh = Utils::ntoh(y1); + uint32_t cilh = (uint32_t)(yh >> 32U); + uint32_t cill = (uint32_t)yh; + uint32_t cihh = (uint32_t)(yl >> 32U); + uint32_t cihl = (uint32_t)yl; + uint32_t cihXlh = cihh ^ cilh; + uint32_t cihXll = cihl ^ cill; + uint32_t aah, aal, abh, abl, ach, acl; + s_bmul32(M0, cihh, hhh, aah, aal); + s_bmul32(M1, cihl, hhl, abh, abl); + s_bmul32(M2, cihh ^ cihl, hhh ^ hhl, ach, acl); + ach ^= aah ^ abh; + acl ^= aal ^ abl; + aal ^= ach; + abh ^= acl; + uint32_t bah, bal, bbh, bbl, bch, bcl; + s_bmul32(M3, cilh, hlh, bah, bal); + s_bmul32(M4, cill, hll, bbh, bbl); + s_bmul32(M5, cilh ^ cill, hlh ^ hll, bch, bcl); + bch ^= bah ^ bbh; + bcl ^= bal ^ bbl; + bal ^= bch; + bbh ^= bcl; + uint32_t cah, cal, cbh, cbl, cch, ccl; + s_bmul32(M6, cihXlh, hhXlh, cah, cal); + s_bmul32(M7, cihXll, hhXll, cbh, cbl); + s_bmul32(M8, cihXlh ^ cihXll, hhXlh ^ hhXll, cch, ccl); + cch ^= cah ^ cbh; + ccl ^= cal ^ cbl; + cal ^= cch; + cbh ^= ccl; + cah ^= bah ^ aah; + cal ^= bal ^ aal; + cbh ^= bbh ^ abh; + cbl ^= bbl ^ abl; + uint64_t zhh = ((uint64_t)aah << 32U) | aal; + uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal); + uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl); + uint64_t zll = ((uint64_t)bbh << 32U) | bbl; + zhh = zhh << 1U | zhl >> 63U; + zhl = zhl << 1U | zlh >> 63U; + zlh = zlh << 1U | zll >> 63U; + zll <<= 1U; + zlh ^= (zll << 63U) ^ (zll << 62U) ^ (zll << 57U); + zhh ^= zlh ^ (zlh >> 1U) ^ (zlh >> 2U) ^ (zlh >> 7U); + zhl ^= zll ^ (zll >> 1U) ^ (zll >> 2U) ^ (zll >> 7U) ^ (zlh << 63U) ^ (zlh << 62U) ^ (zlh << 57U); + y0 = Utils::hton(zhh); + y1 = Utils::hton(zhl); } -} // anonymous namespace +} // anonymous namespace -void AES::GMAC::update(const void *const data, unsigned int len) noexcept +void AES::GMAC::update(const void* const data, unsigned int len) noexcept { - const uint8_t *in = reinterpret_cast(data); - _len += len; + const uint8_t* in = reinterpret_cast(data); + _len += len; #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNIUpdate(in, len); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNIUpdate(in, len); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.pmull) { - p_armUpdate(in, len); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.pmull) { + p_armUpdate(in, len); + return; + } +#endif // ZT_AES_NEON - const uint64_t h0 = _aes.p_k.sw.h[0]; - const uint64_t h1 = _aes.p_k.sw.h[1]; - uint64_t y0 = _y[0]; - uint64_t y1 = _y[1]; + const uint64_t h0 = _aes.p_k.sw.h[0]; + const uint64_t h1 = _aes.p_k.sw.h[1]; + uint64_t y0 = _y[0]; + uint64_t y1 = _y[1]; - if (_rp) { - for (;;) { - if (!len) - return; - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y0 ^= Utils::loadMachineEndian< uint64_t >(_r); - y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); - s_gfmul(h0, h1, y0, y1); - break; - } - } - } + if (_rp) { + for (;;) { + if (! len) + return; + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y0 ^= Utils::loadMachineEndian(_r); + y1 ^= Utils::loadMachineEndian(_r + 8); + s_gfmul(h0, h1, y0, y1); + break; + } + } + } - while (len >= 16) { - y0 ^= Utils::loadMachineEndian< uint64_t >(in); - y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8); - in += 16; - s_gfmul(h0, h1, y0, y1); - len -= 16; - } + while (len >= 16) { + y0 ^= Utils::loadMachineEndian(in); + y1 ^= Utils::loadMachineEndian(in + 8); + in += 16; + s_gfmul(h0, h1, y0, y1); + len -= 16; + } - _y[0] = y0; - _y[1] = y1; + _y[0] = y0; + _y[1] = y1; - for (unsigned int i = 0; i < len; ++i) - _r[i] = in[i]; - _rp = len; // len is always less than 16 here + for (unsigned int i = 0; i < len; ++i) + _r[i] = in[i]; + _rp = len; // len is always less than 16 here } void AES::GMAC::finish(uint8_t tag[16]) noexcept { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNIFinish(tag); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNIFinish(tag); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.pmull) { - p_armFinish(tag); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.pmull) { + p_armFinish(tag); + return; + } +#endif // ZT_AES_NEON - const uint64_t h0 = _aes.p_k.sw.h[0]; - const uint64_t h1 = _aes.p_k.sw.h[1]; - uint64_t y0 = _y[0]; - uint64_t y1 = _y[1]; + const uint64_t h0 = _aes.p_k.sw.h[0]; + const uint64_t h1 = _aes.p_k.sw.h[1]; + uint64_t y0 = _y[0]; + uint64_t y1 = _y[1]; - if (_rp) { - while (_rp < 16) - _r[_rp++] = 0; - y0 ^= Utils::loadMachineEndian< uint64_t >(_r); - y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); - s_gfmul(h0, h1, y0, y1); - } + if (_rp) { + while (_rp < 16) + _r[_rp++] = 0; + y0 ^= Utils::loadMachineEndian(_r); + y1 ^= Utils::loadMachineEndian(_r + 8); + s_gfmul(h0, h1, y0, y1); + } - y0 ^= Utils::hton((uint64_t)_len << 3U); - s_gfmul(h0, h1, y0, y1); + y0 ^= Utils::hton((uint64_t)_len << 3U); + s_gfmul(h0, h1, y0, y1); - uint64_t iv2[2]; - Utils::copy< 12 >(iv2, _iv); + uint64_t iv2[2]; + Utils::copy<12>(iv2, _iv); #if __BYTE_ORDER == __BIG_ENDIAN - reinterpret_cast(iv2)[3] = 0x00000001; + reinterpret_cast(iv2)[3] = 0x00000001; #else - reinterpret_cast(iv2)[3] = 0x01000000; + reinterpret_cast(iv2)[3] = 0x01000000; #endif - _aes.encrypt(iv2, iv2); + _aes.encrypt(iv2, iv2); - Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0); - Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1); + Utils::storeMachineEndian(tag, iv2[0] ^ y0); + Utils::storeMachineEndian(tag + 8, iv2[1] ^ y1); } // AES-CTR ------------------------------------------------------------------------------------------------------------ -void AES::CTR::crypt(const void *const input, unsigned int len) noexcept +void AES::CTR::crypt(const void* const input, unsigned int len) noexcept { - const uint8_t *in = reinterpret_cast(input); - uint8_t *out = _out; + const uint8_t* in = reinterpret_cast(input); + uint8_t* out = _out; #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNICrypt(in, out, len); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNICrypt(in, out, len); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_armCrypt(in, out, len); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.aes) { + p_armCrypt(in, out, len); + return; + } +#endif // ZT_AES_NEON - uint64_t keyStream[2]; - uint32_t ctr = Utils::ntoh(reinterpret_cast(_ctr)[3]); + uint64_t keyStream[2]; + uint32_t ctr = Utils::ntoh(reinterpret_cast(_ctr)[3]); - unsigned int totalLen = _len; - if ((totalLen & 15U)) { - for (;;) { - if (!len) { - _len = (totalLen + len); - return; - } - --len; - out[totalLen++] = *(in++); - if (!(totalLen & 15U)) { - _aes.p_encryptSW(reinterpret_cast(_ctr), reinterpret_cast(keyStream)); - reinterpret_cast(_ctr)[3] = Utils::hton(++ctr); - uint8_t *outblk = out + (totalLen - 16); - for (int i = 0; i < 16; ++i) - outblk[i] ^= reinterpret_cast(keyStream)[i]; - break; - } - } - } + unsigned int totalLen = _len; + if ((totalLen & 15U)) { + for (;;) { + if (! len) { + _len = (totalLen + len); + return; + } + --len; + out[totalLen++] = *(in++); + if (! (totalLen & 15U)) { + _aes.p_encryptSW(reinterpret_cast(_ctr), reinterpret_cast(keyStream)); + reinterpret_cast(_ctr)[3] = Utils::hton(++ctr); + uint8_t* outblk = out + (totalLen - 16); + for (int i = 0; i < 16; ++i) + outblk[i] ^= reinterpret_cast(keyStream)[i]; + break; + } + } + } - out += totalLen; - _len = (totalLen + len); + out += totalLen; + _len = (totalLen + len); - if (likely(len >= 16)) { - const uint32_t *const restrict rk = _aes.p_k.sw.ek; - const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast(_ctr)[0]) ^rk[0]; - const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast(_ctr)[1]) ^rk[1]; - const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast(_ctr)[2]) ^rk[2]; - const uint32_t m8 = 0x000000ff; - const uint32_t m8_8 = 0x0000ff00; - const uint32_t m8_16 = 0x00ff0000; - const uint32_t m8_24 = 0xff000000; - if (likely((((uintptr_t)out & 7U) == 0U) && (((uintptr_t)in & 7U) == 0U))) { - do { - uint32_t s0, s1, s2, s3, t0, t1, t2, t3; - s0 = ctr0rk0; - s1 = ctr1rk1; - s2 = ctr2rk2; - s3 = ctr++ ^ rk[3]; + if (likely(len >= 16)) { + const uint32_t* const restrict rk = _aes.p_k.sw.ek; + const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast(_ctr)[0]) ^ rk[0]; + const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast(_ctr)[1]) ^ rk[1]; + const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast(_ctr)[2]) ^ rk[2]; + const uint32_t m8 = 0x000000ff; + const uint32_t m8_8 = 0x0000ff00; + const uint32_t m8_16 = 0x00ff0000; + const uint32_t m8_24 = 0xff000000; + if (likely((((uintptr_t)out & 7U) == 0U) && (((uintptr_t)in & 7U) == 0U))) { + do { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + s0 = ctr0rk0; + s1 = ctr1rk1; + s2 = ctr2rk2; + s3 = ctr++ ^ rk[3]; - const uint64_t in0 = *reinterpret_cast(in); - const uint64_t in1 = *reinterpret_cast(in + 8); - in += 16; + const uint64_t in0 = *reinterpret_cast(in); + const uint64_t in1 = *reinterpret_cast(in + 8); + in += 16; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) + ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) + ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) + ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) + ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - *reinterpret_cast(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); - *reinterpret_cast(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); - out += 16; - } while ((len -= 16) >= 16); - } else { - do { - uint32_t s0, s1, s2, s3, t0, t1, t2, t3; - s0 = ctr0rk0; - s1 = ctr1rk1; - s2 = ctr2rk2; - s3 = ctr++ ^ rk[3]; + *reinterpret_cast(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); + *reinterpret_cast(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); + out += 16; + } while ((len -= 16) >= 16); + } + else { + do { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + s0 = ctr0rk0; + s1 = ctr1rk1; + s2 = ctr2rk2; + s3 = ctr++ ^ rk[3]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) + ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) + ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) + ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) + ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - out[0] = in[0] ^ (uint8_t)(s0 >> 24U); - out[1] = in[1] ^ (uint8_t)(s0 >> 16U); - out[2] = in[2] ^ (uint8_t)(s0 >> 8U); - out[3] = in[3] ^ (uint8_t)s0; - out[4] = in[4] ^ (uint8_t)(s1 >> 24U); - out[5] = in[5] ^ (uint8_t)(s1 >> 16U); - out[6] = in[6] ^ (uint8_t)(s1 >> 8U); - out[7] = in[7] ^ (uint8_t)s1; - out[8] = in[8] ^ (uint8_t)(s2 >> 24U); - out[9] = in[9] ^ (uint8_t)(s2 >> 16U); - out[10] = in[10] ^ (uint8_t)(s2 >> 8U); - out[11] = in[11] ^ (uint8_t)s2; - out[12] = in[12] ^ (uint8_t)(s3 >> 24U); - out[13] = in[13] ^ (uint8_t)(s3 >> 16U); - out[14] = in[14] ^ (uint8_t)(s3 >> 8U); - out[15] = in[15] ^ (uint8_t)s3; - out += 16; - in += 16; - } while ((len -= 16) >= 16); - } - reinterpret_cast(_ctr)[3] = Utils::hton(ctr); - } + out[0] = in[0] ^ (uint8_t)(s0 >> 24U); + out[1] = in[1] ^ (uint8_t)(s0 >> 16U); + out[2] = in[2] ^ (uint8_t)(s0 >> 8U); + out[3] = in[3] ^ (uint8_t)s0; + out[4] = in[4] ^ (uint8_t)(s1 >> 24U); + out[5] = in[5] ^ (uint8_t)(s1 >> 16U); + out[6] = in[6] ^ (uint8_t)(s1 >> 8U); + out[7] = in[7] ^ (uint8_t)s1; + out[8] = in[8] ^ (uint8_t)(s2 >> 24U); + out[9] = in[9] ^ (uint8_t)(s2 >> 16U); + out[10] = in[10] ^ (uint8_t)(s2 >> 8U); + out[11] = in[11] ^ (uint8_t)s2; + out[12] = in[12] ^ (uint8_t)(s3 >> 24U); + out[13] = in[13] ^ (uint8_t)(s3 >> 16U); + out[14] = in[14] ^ (uint8_t)(s3 >> 8U); + out[15] = in[15] ^ (uint8_t)s3; + out += 16; + in += 16; + } while ((len -= 16) >= 16); + } + reinterpret_cast(_ctr)[3] = Utils::hton(ctr); + } - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - while (len) { - --len; - *(out++) = *(in++); - } + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + while (len) { + --len; + *(out++) = *(in++); + } } void AES::CTR::finish() noexcept { - uint8_t tmp[16]; - const unsigned int rem = _len & 15U; - if (rem) { - _aes.encrypt(_ctr, tmp); - for (unsigned int i = 0, j = _len - rem; i < rem; ++i) - _out[j + i] ^= tmp[i]; - } + uint8_t tmp[16]; + const unsigned int rem = _len & 15U; + if (rem) { + _aes.encrypt(_ctr, tmp); + for (unsigned int i = 0, j = _len - rem; i < rem; ++i) + _out[j + i] ^= tmp[i]; + } } // Software AES and AES key expansion --------------------------------------------------------------------------------- -const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, - 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, - 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, - 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, - 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, - 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, - 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, - 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a}; -const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, - 0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, - 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, - 0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, - 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, - 0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, - 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, - 0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616}; -const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, - 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, - 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, - 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, - 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, - 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, - 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, - 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742}; -const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, - 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, - 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; -const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000}; +const uint32_t AES::Te0[256] = { + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, + 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, + 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, + 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, + 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, + 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, + 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, + 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, + 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, + 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, + 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, + 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, + 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, + 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, + 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, + 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, + 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, + 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, + 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, + 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, + 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, + 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, + 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, + 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, + 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, + 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +}; +const uint32_t AES::Te4[256] = { + 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, + 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, + 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, + 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, + 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, + 0xd8d8d8d8, 0x31313131, 0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, + 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, + 0x75757575, 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, + 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, + 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, + 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, + 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, + 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, + 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, + 0xf3f3f3f3, 0xd2d2d2d2, 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, + 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, + 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, + 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, + 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, + 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, + 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, + 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, + 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, + 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, + 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, + 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, + 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, + 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, + 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616 +}; +const uint32_t AES::Td0[256] = { + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, + 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, + 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, + 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, + 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, + 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, + 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, + 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, + 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, + 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, + 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, + 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, + 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, + 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, + 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, + 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, + 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, + 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, + 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, + 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, + 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, + 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, + 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, + 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, + 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, + 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +}; +const uint8_t AES::Td4[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, + 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, + 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, + 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, + 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, + 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, + 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, + 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, + 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, + 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, + 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, + 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, + 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; +const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 }; -void AES::p_initSW(const uint8_t *key) noexcept +void AES::p_initSW(const uint8_t* key) noexcept { - uint32_t *rk = p_k.sw.ek; + uint32_t* rk = p_k.sw.ek; - rk[0] = Utils::loadBigEndian< uint32_t >(key); - rk[1] = Utils::loadBigEndian< uint32_t >(key + 4); - rk[2] = Utils::loadBigEndian< uint32_t >(key + 8); - rk[3] = Utils::loadBigEndian< uint32_t >(key + 12); - rk[4] = Utils::loadBigEndian< uint32_t >(key + 16); - rk[5] = Utils::loadBigEndian< uint32_t >(key + 20); - rk[6] = Utils::loadBigEndian< uint32_t >(key + 24); - rk[7] = Utils::loadBigEndian< uint32_t >(key + 28); - for (int i = 0;;) { - uint32_t temp = rk[7]; - rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; - rk[9] = rk[1] ^ rk[8]; - rk[10] = rk[2] ^ rk[9]; - rk[11] = rk[3] ^ rk[10]; - if (++i == 7) - break; - temp = rk[11]; - rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp) & 0xffU) & 0x000000ffU); - rk[13] = rk[5] ^ rk[12]; - rk[14] = rk[6] ^ rk[13]; - rk[15] = rk[7] ^ rk[14]; - rk += 8; - } + rk[0] = Utils::loadBigEndian(key); + rk[1] = Utils::loadBigEndian(key + 4); + rk[2] = Utils::loadBigEndian(key + 8); + rk[3] = Utils::loadBigEndian(key + 12); + rk[4] = Utils::loadBigEndian(key + 16); + rk[5] = Utils::loadBigEndian(key + 20); + rk[6] = Utils::loadBigEndian(key + 24); + rk[7] = Utils::loadBigEndian(key + 28); + for (int i = 0;;) { + uint32_t temp = rk[7]; + rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) + ^ (Te0[(temp)&0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (++i == 7) + break; + temp = rk[11]; + rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) + ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp)&0xffU) & 0x000000ffU); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + rk += 8; + } - p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h); - p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); - p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); + p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h); + p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); + p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); - for (int i = 0; i < 60; ++i) - p_k.sw.dk[i] = p_k.sw.ek[i]; - rk = p_k.sw.dk; + for (int i = 0; i < 60; ++i) + p_k.sw.dk[i] = p_k.sw.ek[i]; + rk = p_k.sw.dk; - for (int i = 0, j = 56; i < j; i += 4, j -= 4) { - uint32_t temp = rk[i]; - rk[i] = rk[j]; - rk[j] = temp; - temp = rk[i + 1]; - rk[i + 1] = rk[j + 1]; - rk[j + 1] = temp; - temp = rk[i + 2]; - rk[i + 2] = rk[j + 2]; - rk[j + 2] = temp; - temp = rk[i + 3]; - rk[i + 3] = rk[j + 3]; - rk[j + 3] = temp; - } - for (int i = 1; i < 14; ++i) { - rk += 4; - rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU); - rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU); - rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU); - rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU); - } + for (int i = 0, j = 56; i < j; i += 4, j -= 4) { + uint32_t temp = rk[i]; + rk[i] = rk[j]; + rk[j] = temp; + temp = rk[i + 1]; + rk[i + 1] = rk[j + 1]; + rk[j + 1] = temp; + temp = rk[i + 2]; + rk[i + 2] = rk[j + 2]; + rk[j + 2] = temp; + temp = rk[i + 3]; + rk[i + 3] = rk[j + 3]; + rk[j + 3] = temp; + } + for (int i = 1; i < 14; ++i) { + rk += 4; + rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU) + ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU); + rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU) + ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU); + rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU) + ^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU); + rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU) + ^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU); + } } -void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept +void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept { - const uint32_t *const restrict rk = p_k.sw.ek; - const uint32_t m8 = 0x000000ff; - const uint32_t m8_8 = 0x0000ff00; - const uint32_t m8_16 = 0x00ff0000; - const uint32_t m8_24 = 0xff000000; - uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; - uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; - uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; - uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; + const uint32_t* const restrict rk = p_k.sw.ek; + const uint32_t m8 = 0x000000ff; + const uint32_t m8_8 = 0x0000ff00; + const uint32_t m8_16 = 0x00ff0000; + const uint32_t m8_24 = 0xff000000; + uint32_t s0 = Utils::loadBigEndian(in) ^ rk[0]; + uint32_t s1 = Utils::loadBigEndian(in + 4) ^ rk[1]; + uint32_t s2 = Utils::loadBigEndian(in + 8) ^ rk[2]; + uint32_t s3 = Utils::loadBigEndian(in + 12) ^ rk[3]; - uint32_t t0, t1, t2, t3; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + uint32_t t0, t1, t2, t3; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) + ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) + ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) + ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) + ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - Utils::storeBigEndian< uint32_t >(out, s0); - Utils::storeBigEndian< uint32_t >(out + 4, s1); - Utils::storeBigEndian< uint32_t >(out + 8, s2); - Utils::storeBigEndian< uint32_t >(out + 12, s3); + Utils::storeBigEndian(out, s0); + Utils::storeBigEndian(out + 4, s1); + Utils::storeBigEndian(out + 8, s2); + Utils::storeBigEndian(out + 12, s3); } -void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept +void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept { - const uint32_t *restrict rk = p_k.sw.dk; - const uint32_t m8 = 0x000000ff; - uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; - uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; - uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; - uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; + const uint32_t* restrict rk = p_k.sw.dk; + const uint32_t m8 = 0x000000ff; + uint32_t s0 = Utils::loadBigEndian(in) ^ rk[0]; + uint32_t s1 = Utils::loadBigEndian(in + 4) ^ rk[1]; + uint32_t s2 = Utils::loadBigEndian(in + 8) ^ rk[2]; + uint32_t s3 = Utils::loadBigEndian(in + 12) ^ rk[3]; - uint32_t t0, t1, t2, t3; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[5]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[6]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[7]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[8]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[9]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[10]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[11]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[12]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[13]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[14]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[15]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[16]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[17]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[18]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[19]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[20]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[21]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[22]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[23]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[24]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[25]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[26]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[27]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[28]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[29]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[30]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[31]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[32]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[33]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[34]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[35]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[36]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[37]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[38]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[39]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[40]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[41]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[42]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[43]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[44]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[45]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[46]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[47]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[48]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[49]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[50]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[51]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[52]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; - s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56]; - s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57]; - s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58]; - s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59]; + uint32_t t0, t1, t2, t3; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[5]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[6]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[7]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[8]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[9]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[10]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[11]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[12]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[13]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[14]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[15]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[16]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[17]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[18]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[19]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[20]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[21]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[22]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[23]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[24]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[25]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[26]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[27]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[28]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[29]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[30]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[31]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[32]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[33]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[34]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[35]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[36]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[37]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[38]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[39]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[40]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[41]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[42]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[43]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[44]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[45]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[46]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[47]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[48]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[49]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[50]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[51]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[52]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; + s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8]) + ^ rk[56]; + s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8]) + ^ rk[57]; + s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8]) + ^ rk[58]; + s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8]) + ^ rk[59]; - Utils::storeBigEndian< uint32_t >(out, s0); - Utils::storeBigEndian< uint32_t >(out + 4, s1); - Utils::storeBigEndian< uint32_t >(out + 8, s2); - Utils::storeBigEndian< uint32_t >(out + 12, s3); + Utils::storeBigEndian(out, s0); + Utils::storeBigEndian(out + 4, s1); + Utils::storeBigEndian(out + 8, s2); + Utils::storeBigEndian(out + 12, s3); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/AES.hpp b/core/AES.hpp index 2216d0106..77f21ee6b 100644 --- a/core/AES.hpp +++ b/core/AES.hpp @@ -15,16 +15,16 @@ #define ZT_AES_HPP #include "Constants.hpp" -#include "Utils.hpp" #include "SHA512.hpp" +#include "Utils.hpp" // Uncomment to disable all hardware acceleration (usually for testing) //#define ZT_AES_NO_ACCEL -#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) +#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) #define ZT_AES_AESNI 1 #endif -#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) +#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) #define ZT_AES_NEON 1 #endif @@ -40,558 +40,562 @@ namespace ZeroTier { * This includes hardware acceleration for certain processors. The software * mode is fallback and is significantly slower. */ -class AES -{ -public: - /** - * @return True if this system has hardware AES acceleration - */ - static ZT_INLINE bool accelerated() - { +class AES { + public: + /** + * @return True if this system has hardware AES acceleration + */ + static ZT_INLINE bool accelerated() + { #ifdef ZT_AES_NO_ACCEL - return false; + return false; #else #ifdef ZT_AES_AESNI - return Utils::CPUID.aes; + return Utils::CPUID.aes; #endif #ifdef ZT_AES_NEON - return Utils::ARMCAP.aes; + return Utils::ARMCAP.aes; #endif #endif - } + } - /** - * Create an un-initialized AES instance (must call init() before use) - */ - ZT_INLINE AES() noexcept - {} + /** + * Create an un-initialized AES instance (must call init() before use) + */ + ZT_INLINE AES() noexcept + { + } - /** - * Create an AES instance with the given key - * - * @param key 256-bit key - */ - explicit ZT_INLINE AES(const void *const key) noexcept - { this->init(key); } + /** + * Create an AES instance with the given key + * + * @param key 256-bit key + */ + explicit ZT_INLINE AES(const void* const key) noexcept + { + this->init(key); + } - ZT_INLINE ~AES() - { Utils::burn(&p_k, sizeof(p_k)); } + ZT_INLINE ~AES() + { + Utils::burn(&p_k, sizeof(p_k)); + } - /** - * Set (or re-set) this AES256 cipher's key - * - * @param key 256-bit / 32-byte key - */ - ZT_INLINE void init(const void *const key) noexcept - { + /** + * Set (or re-set) this AES256 cipher's key + * + * @param key 256-bit / 32-byte key + */ + ZT_INLINE void init(const void* const key) noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_init_aesni(reinterpret_cast(key)); - return; - } + if (likely(Utils::CPUID.aes)) { + p_init_aesni(reinterpret_cast(key)); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_init_armneon_crypto(reinterpret_cast(key)); - return; - } + if (Utils::ARMCAP.aes) { + p_init_armneon_crypto(reinterpret_cast(key)); + return; + } #endif - p_initSW(reinterpret_cast(key)); - } + p_initSW(reinterpret_cast(key)); + } - /** - * Encrypt a single AES block - * - * @param in Input block - * @param out Output block (can be same as input) - */ - ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept - { + /** + * Encrypt a single AES block + * + * @param in Input block + * @param out Output block (can be same as input) + */ + ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_encrypt_aesni(in, out); - return; - } + if (likely(Utils::CPUID.aes)) { + p_encrypt_aesni(in, out); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_encrypt_armneon_crypto(in, out); - return; - } + if (Utils::ARMCAP.aes) { + p_encrypt_armneon_crypto(in, out); + return; + } #endif - p_encryptSW(reinterpret_cast(in), reinterpret_cast(out)); - } + p_encryptSW(reinterpret_cast(in), reinterpret_cast(out)); + } - /** - * Decrypt a single AES block - * - * @param in Input block - * @param out Output block (can be same as input) - */ - ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept - { + /** + * Decrypt a single AES block + * + * @param in Input block + * @param out Output block (can be same as input) + */ + ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_decrypt_aesni(in, out); - return; - } + if (likely(Utils::CPUID.aes)) { + p_decrypt_aesni(in, out); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_decrypt_armneon_crypto(in, out); - return; - } + if (Utils::ARMCAP.aes) { + p_decrypt_armneon_crypto(in, out); + return; + } #endif - p_decryptSW(reinterpret_cast(in), reinterpret_cast(out)); - } + p_decryptSW(reinterpret_cast(in), reinterpret_cast(out)); + } - class GMACSIVEncryptor; - class GMACSIVDecryptor; + class GMACSIVEncryptor; + class GMACSIVDecryptor; - /** - * Streaming GMAC calculator - */ - class GMAC - { - friend class GMACSIVEncryptor; - friend class GMACSIVDecryptor; + /** + * Streaming GMAC calculator + */ + class GMAC { + friend class GMACSIVEncryptor; + friend class GMACSIVDecryptor; - public: - /** - * @return True if this system has hardware GMAC acceleration - */ - static ZT_INLINE bool accelerated() - { + public: + /** + * @return True if this system has hardware GMAC acceleration + */ + static ZT_INLINE bool accelerated() + { #ifdef ZT_AES_AESNI - return Utils::CPUID.aes; + return Utils::CPUID.aes; #else #ifdef ZT_AES_NEON - return Utils::ARMCAP.pmull; + return Utils::ARMCAP.pmull; #else - return false; + return false; #endif #endif - } + } - /** - * Create a new instance of GMAC (must be initialized with init() before use) - * - * @param aes Keyed AES instance to use - */ - ZT_INLINE GMAC(const AES &aes) : _aes(aes) - {} + /** + * Create a new instance of GMAC (must be initialized with init() before use) + * + * @param aes Keyed AES instance to use + */ + ZT_INLINE GMAC(const AES& aes) : _aes(aes) + { + } - /** - * Reset and initialize for a new GMAC calculation - * - * @param iv 96-bit initialization vector (pad with zeroes if actual IV is shorter) - */ - ZT_INLINE void init(const uint8_t iv[12]) noexcept - { - _rp = 0; - _len = 0; + /** + * Reset and initialize for a new GMAC calculation + * + * @param iv 96-bit initialization vector (pad with zeroes if actual IV is shorter) + */ + ZT_INLINE void init(const uint8_t iv[12]) noexcept + { + _rp = 0; + _len = 0; - // We fill the least significant 32 bits in the _iv field with 1 since in GCM mode - // this would hold the counter, but we're not doing GCM just GMAC. That means the - // counter always stays just 1. -#ifdef ZT_AES_AESNI // also implies an x64 processor - *reinterpret_cast(_iv) = *reinterpret_cast(iv); - *reinterpret_cast(_iv + 8) = *reinterpret_cast(iv + 8); - *reinterpret_cast(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order + // We fill the least significant 32 bits in the _iv field with 1 since in GCM mode + // this would hold the counter, but we're not doing GCM just GMAC. That means the + // counter always stays just 1. +#ifdef ZT_AES_AESNI // also implies an x64 processor + *reinterpret_cast(_iv) = *reinterpret_cast(iv); + *reinterpret_cast(_iv + 8) = *reinterpret_cast(iv + 8); + *reinterpret_cast(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order #else - Utils::copy<12>(_iv, iv); - _iv[12] = 0; - _iv[13] = 0; - _iv[14] = 0; - _iv[15] = 1; + Utils::copy<12>(_iv, iv); + _iv[12] = 0; + _iv[13] = 0; + _iv[14] = 0; + _iv[15] = 1; #endif - _y[0] = 0; - _y[1] = 0; - } + _y[0] = 0; + _y[1] = 0; + } - /** - * Process data through GMAC - * - * @param data Bytes to process - * @param len Length of input - */ - void update(const void *data, unsigned int len) noexcept; + /** + * Process data through GMAC + * + * @param data Bytes to process + * @param len Length of input + */ + void update(const void* data, unsigned int len) noexcept; - /** - * Process any remaining cached bytes and generate tag - * - * Don't call finish() more than once or you'll get an invalid result. - * - * @param tag 128-bit GMAC tag (can be truncated) - */ - void finish(uint8_t tag[16]) noexcept; + /** + * Process any remaining cached bytes and generate tag + * + * Don't call finish() more than once or you'll get an invalid result. + * + * @param tag 128-bit GMAC tag (can be truncated) + */ + void finish(uint8_t tag[16]) noexcept; - private: + private: #ifdef ZT_AES_AESNI - void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept; - void p_aesNIFinish(uint8_t tag[16]) noexcept; + void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept; + void p_aesNIFinish(uint8_t tag[16]) noexcept; #endif #ifdef ZT_AES_NEON - void p_armUpdate(const uint8_t *in, unsigned int len) noexcept; - void p_armFinish(uint8_t tag[16]) noexcept; + void p_armUpdate(const uint8_t* in, unsigned int len) noexcept; + void p_armFinish(uint8_t tag[16]) noexcept; #endif - const AES &_aes; - unsigned int _rp; - unsigned int _len; - uint8_t _r[16]; // remainder - uint8_t _iv[16]; - uint64_t _y[2]; - }; + const AES& _aes; + unsigned int _rp; + unsigned int _len; + uint8_t _r[16]; // remainder + uint8_t _iv[16]; + uint64_t _y[2]; + }; - /** - * Streaming AES-CTR encrypt/decrypt - * - * NOTE: this doesn't support overflow of the counter in the least significant 32 bits. - * We will never encrypt more than a tiny fraction of 2^32 blocks, so this is left out as - * an optimization. - */ - class CTR - { - friend class GMACSIVEncryptor; - friend class GMACSIVDecryptor; + /** + * Streaming AES-CTR encrypt/decrypt + * + * NOTE: this doesn't support overflow of the counter in the least significant 32 bits. + * We will never encrypt more than a tiny fraction of 2^32 blocks, so this is left out as + * an optimization. + */ + class CTR { + friend class GMACSIVEncryptor; + friend class GMACSIVDecryptor; - public: - ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes) - {} + public: + ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes) + { + } - /** - * Initialize this CTR instance to encrypt a new stream - * - * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) - * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) - */ - ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept - { - Utils::copy< 16 >(_ctr, iv); - _out = reinterpret_cast(output); - _len = 0; - } + /** + * Initialize this CTR instance to encrypt a new stream + * + * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) + * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) + */ + ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept + { + Utils::copy<16>(_ctr, iv); + _out = reinterpret_cast(output); + _len = 0; + } - /** - * Initialize this CTR instance to encrypt a new stream - * - * @param iv Unique initialization vector - * @param ic Initial counter (must be in big-endian byte order!) - * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) - */ - ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept - { - Utils::copy< 12 >(_ctr, iv); - reinterpret_cast(_ctr)[3] = ic; - _out = reinterpret_cast(output); - _len = 0; - } + /** + * Initialize this CTR instance to encrypt a new stream + * + * @param iv Unique initialization vector + * @param ic Initial counter (must be in big-endian byte order!) + * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) + */ + ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept + { + Utils::copy<12>(_ctr, iv); + reinterpret_cast(_ctr)[3] = ic; + _out = reinterpret_cast(output); + _len = 0; + } - /** - * Encrypt or decrypt data, writing result to the output provided to init() - * - * @param input Input data - * @param len Length of input - */ - void crypt(const void *input, unsigned int len) noexcept; + /** + * Encrypt or decrypt data, writing result to the output provided to init() + * + * @param input Input data + * @param len Length of input + */ + void crypt(const void* input, unsigned int len) noexcept; - /** - * Finish any remaining bytes if total bytes processed wasn't a multiple of 16 - * - * Don't call more than once for a given stream or data may be corrupted. - */ - void finish() noexcept; + /** + * Finish any remaining bytes if total bytes processed wasn't a multiple of 16 + * + * Don't call more than once for a given stream or data may be corrupted. + */ + void finish() noexcept; - private: + private: #ifdef ZT_AES_AESNI - void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; + void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept; #endif #ifdef ZT_AES_NEON - void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; + void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept; #endif - const AES &_aes; - uint64_t _ctr[2]; - uint8_t *_out; - unsigned int _len; - }; + const AES& _aes; + uint64_t _ctr[2]; + uint8_t* _out; + unsigned int _len; + }; - /** - * Encryptor for AES-GMAC-SIV. - * - * Encryption requires two passes. The first pass starts after init - * with aad (if any) followed by update1() and finish1(). Then the - * update2() and finish2() methods must be used over the same data - * (but NOT AAD) again. - * - * This supports encryption of a maximum of 2^31 bytes of data per - * call to init(). - */ - class GMACSIVEncryptor - { - public: - /** - * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances - * - * @param k0 First of two AES instances keyed with K0 - * @param k1 Second of two AES instances keyed with K1 - */ - ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept : - _gmac(k0), - _ctr(k1) - {} + /** + * Encryptor for AES-GMAC-SIV. + * + * Encryption requires two passes. The first pass starts after init + * with aad (if any) followed by update1() and finish1(). Then the + * update2() and finish2() methods must be used over the same data + * (but NOT AAD) again. + * + * This supports encryption of a maximum of 2^31 bytes of data per + * call to init(). + */ + class GMACSIVEncryptor { + public: + /** + * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances + * + * @param k0 First of two AES instances keyed with K0 + * @param k1 Second of two AES instances keyed with K1 + */ + ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept + : _gmac(k0) + , _ctr(k1) + { + } - /** - * Initialize AES-GMAC-SIV - * - * @param iv IV in network byte order (byte order in which it will appear on the wire) - * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! - */ - ZT_INLINE void init(const uint64_t iv, void *const output) noexcept - { - // Output buffer to receive the result of AES-CTR encryption. - _output = output; + /** + * Initialize AES-GMAC-SIV + * + * @param iv IV in network byte order (byte order in which it will appear on the wire) + * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! + */ + ZT_INLINE void init(const uint64_t iv, void* const output) noexcept + { + // Output buffer to receive the result of AES-CTR encryption. + _output = output; - // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). - _tag[0] = iv; - _tag[1] = 0; - _gmac.init(reinterpret_cast(_tag)); - } + // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). + _tag[0] = iv; + _tag[1] = 0; + _gmac.init(reinterpret_cast(_tag)); + } - /** - * Process AAD (additional authenticated data) that is not being encrypted. - * - * This MUST be called before update1() and finish1() if there is AAD to - * be included. This also MUST NOT be called more than once as the current - * code only supports one chunk of AAD. - * - * @param aad Additional authenticated data - * @param len Length of AAD in bytes - */ - ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept - { - // Feed ADD into GMAC first - _gmac.update(aad, len); + /** + * Process AAD (additional authenticated data) that is not being encrypted. + * + * This MUST be called before update1() and finish1() if there is AAD to + * be included. This also MUST NOT be called more than once as the current + * code only supports one chunk of AAD. + * + * @param aad Additional authenticated data + * @param len Length of AAD in bytes + */ + ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept + { + // Feed ADD into GMAC first + _gmac.update(aad, len); - // End of AAD is padded to a multiple of 16 bytes to ensure unique encoding. - len &= 0xfU; - if (len != 0) - _gmac.update(Utils::ZERO256, 16U - len); - } + // End of AAD is padded to a multiple of 16 bytes to ensure unique encoding. + len &= 0xfU; + if (len != 0) + _gmac.update(Utils::ZERO256, 16U - len); + } - /** - * First pass plaintext input function - * - * @param input Plaintext chunk - * @param len Length of plaintext chunk - */ - ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept - { _gmac.update(input, len); } + /** + * First pass plaintext input function + * + * @param input Plaintext chunk + * @param len Length of plaintext chunk + */ + ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept + { + _gmac.update(input, len); + } - /** - * Finish first pass, compute CTR IV, initialize second pass. - */ - ZT_INLINE void finish1() noexcept - { - // Compute 128-bit GMAC tag. - uint64_t tmp[2]; - _gmac.finish(reinterpret_cast(tmp)); + /** + * Finish first pass, compute CTR IV, initialize second pass. + */ + ZT_INLINE void finish1() noexcept + { + // Compute 128-bit GMAC tag. + uint64_t tmp[2]; + _gmac.finish(reinterpret_cast(tmp)); - // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to - // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV - // this get split into the packet ID (64 bits) and the MAC (64 bits) in each - // packet and then recombined on receipt for legacy reasons (but with no - // cryptographic or performance impact). - _tag[1] = tmp[0] ^ tmp[1]; // NOTE: _tag[0] already contains message IV, see init() - _ctr._aes.encrypt(_tag, _tag); + // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to + // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV + // this get split into the packet ID (64 bits) and the MAC (64 bits) in each + // packet and then recombined on receipt for legacy reasons (but with no + // cryptographic or performance impact). + _tag[1] = tmp[0] ^ tmp[1]; // NOTE: _tag[0] already contains message IV, see init() + _ctr._aes.encrypt(_tag, _tag); - // Initialize CTR with 96-bit CTR nonce and 32-bit counter. The counter - // incorporates 31 more bits of entropy which should raise our security margin - // a bit, but this is not included in the worst case analysis of GMAC-SIV. - // The most significant bit of the counter is masked to zero to allow up to - // 2^31 bytes to be encrypted before the counter loops. Some CTR implementations - // increment the whole big-endian 128-bit integer in which case this could be - // used for more than 2^31 bytes, but ours does not for performance reasons - // and so 2^31 should be considered the input limit. - tmp[0] = _tag[0]; - tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); - _ctr.init(reinterpret_cast(tmp), _output); - } + // Initialize CTR with 96-bit CTR nonce and 32-bit counter. The counter + // incorporates 31 more bits of entropy which should raise our security margin + // a bit, but this is not included in the worst case analysis of GMAC-SIV. + // The most significant bit of the counter is masked to zero to allow up to + // 2^31 bytes to be encrypted before the counter loops. Some CTR implementations + // increment the whole big-endian 128-bit integer in which case this could be + // used for more than 2^31 bytes, but ours does not for performance reasons + // and so 2^31 should be considered the input limit. + tmp[0] = _tag[0]; + tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); + _ctr.init(reinterpret_cast(tmp), _output); + } - /** - * Second pass plaintext input function - * - * The same plaintext must be fed in the second time. Chunk boundaries - * (between calls to update2()) do not have to be the same, just the order - * of the bytes. - * - * @param input Plaintext chunk - * @param len Length of plaintext chunk - */ - ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept - { _ctr.crypt(input, len); } + /** + * Second pass plaintext input function + * + * The same plaintext must be fed in the second time. Chunk boundaries + * (between calls to update2()) do not have to be the same, just the order + * of the bytes. + * + * @param input Plaintext chunk + * @param len Length of plaintext chunk + */ + ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept + { + _ctr.crypt(input, len); + } - /** - * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block - * - * The returned pointer remains valid as long as this object exists and init() - * is not called again. - * - * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) - */ - ZT_INLINE const uint64_t *finish2() - { - _ctr.finish(); - return _tag; - } + /** + * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block + * + * The returned pointer remains valid as long as this object exists and init() + * is not called again. + * + * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) + */ + ZT_INLINE const uint64_t* finish2() + { + _ctr.finish(); + return _tag; + } - private: - void *_output; - uint64_t _tag[2]; - AES::GMAC _gmac; - AES::CTR _ctr; - }; + private: + void* _output; + uint64_t _tag[2]; + AES::GMAC _gmac; + AES::CTR _ctr; + }; - /** - * Decryptor for AES-GMAC-SIV. - * - * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. - */ - class GMACSIVDecryptor - { - public: - ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept: - _ctr(k1), - _gmac(k0) - {} + /** + * Decryptor for AES-GMAC-SIV. + * + * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. + */ + class GMACSIVDecryptor { + public: + ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept + : _ctr(k1) + , _gmac(k0) + { + } - /** - * Initialize decryptor for a new message - * - * @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption - * @param output Buffer in which to write output plaintext (must be large enough!) - */ - ZT_INLINE void init(const uint64_t tag[2], void *const output) noexcept - { - uint64_t tmp[2]; - tmp[0] = tag[0]; - tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); - _ctr.init(reinterpret_cast(tmp), output); + /** + * Initialize decryptor for a new message + * + * @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption + * @param output Buffer in which to write output plaintext (must be large enough!) + */ + ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept + { + uint64_t tmp[2]; + tmp[0] = tag[0]; + tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); + _ctr.init(reinterpret_cast(tmp), output); - _ctr._aes.decrypt(tag, _ivMac); + _ctr._aes.decrypt(tag, _ivMac); - tmp[0] = _ivMac[0]; - tmp[1] = 0; - _gmac.init(reinterpret_cast(tmp)); + tmp[0] = _ivMac[0]; + tmp[1] = 0; + _gmac.init(reinterpret_cast(tmp)); - _output = output; - _decryptedLen = 0; - } + _output = output; + _decryptedLen = 0; + } - /** - * Process AAD (additional authenticated data) that wasn't encrypted - * - * @param aad Additional authenticated data - * @param len Length of AAD in bytes - */ - ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept - { - _gmac.update(aad, len); - len &= 0xfU; - if (len != 0) - _gmac.update(Utils::ZERO256, 16 - len); - } + /** + * Process AAD (additional authenticated data) that wasn't encrypted + * + * @param aad Additional authenticated data + * @param len Length of AAD in bytes + */ + ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept + { + _gmac.update(aad, len); + len &= 0xfU; + if (len != 0) + _gmac.update(Utils::ZERO256, 16 - len); + } - /** - * Feed ciphertext into the decryptor - * - * Unlike encryption, GMAC-SIV decryption requires only one pass. - * - * @param input Input ciphertext - * @param len Length of ciphertext - */ - ZT_INLINE void update(const void *const input, const unsigned int len) noexcept - { - _ctr.crypt(input, len); - _decryptedLen += len; - } + /** + * Feed ciphertext into the decryptor + * + * Unlike encryption, GMAC-SIV decryption requires only one pass. + * + * @param input Input ciphertext + * @param len Length of ciphertext + */ + ZT_INLINE void update(const void* const input, const unsigned int len) noexcept + { + _ctr.crypt(input, len); + _decryptedLen += len; + } - /** - * Flush decryption, compute MAC, and verify - * - * @return True if resulting plaintext (and AAD) pass message authentication check - */ - ZT_INLINE bool finish() noexcept - { - _ctr.finish(); + /** + * Flush decryption, compute MAC, and verify + * + * @return True if resulting plaintext (and AAD) pass message authentication check + */ + ZT_INLINE bool finish() noexcept + { + _ctr.finish(); - uint64_t gmacTag[2]; - _gmac.update(_output, _decryptedLen); - _gmac.finish(reinterpret_cast(gmacTag)); - return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; - } + uint64_t gmacTag[2]; + _gmac.update(_output, _decryptedLen); + _gmac.finish(reinterpret_cast(gmacTag)); + return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; + } - private: - uint64_t _ivMac[2]; - AES::CTR _ctr; - AES::GMAC _gmac; - void *_output; - unsigned int _decryptedLen; - }; + private: + uint64_t _ivMac[2]; + AES::CTR _ctr; + AES::GMAC _gmac; + void* _output; + unsigned int _decryptedLen; + }; -private: - static const uint32_t Te0[256]; - static const uint32_t Te4[256]; - static const uint32_t Td0[256]; - static const uint8_t Td4[256]; - static const uint32_t rcon[15]; + private: + static const uint32_t Te0[256]; + static const uint32_t Te4[256]; + static const uint32_t Td0[256]; + static const uint8_t Td4[256]; + static const uint32_t rcon[15]; - void p_initSW(const uint8_t *key) noexcept; - void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept; - void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept; + void p_initSW(const uint8_t* key) noexcept; + void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept; + void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept; - union - { + union { #ifdef ZT_AES_AESNI - struct - { - __m128i k[28]; - __m128i h[4]; // h, hh, hhh, hhhh - __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. - } ni; + struct { + __m128i k[28]; + __m128i h[4]; // h, hh, hhh, hhhh + __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. + } ni; #endif #ifdef ZT_AES_NEON - struct - { - uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens - uint8x16_t ek[15]; - uint8x16_t dk[15]; - uint8x16_t h; - } neon; + struct { + uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens + uint8x16_t ek[15]; + uint8x16_t dk[15]; + uint8x16_t h; + } neon; #endif - struct - { - uint64_t h[2]; - uint32_t ek[60]; - uint32_t dk[60]; - } sw; - } p_k; + struct { + uint64_t h[2]; + uint32_t ek[60]; + uint32_t dk[60]; + } sw; + } p_k; #ifdef ZT_AES_AESNI - void p_init_aesni(const uint8_t *key) noexcept; - void p_encrypt_aesni(const void *in, void *out) const noexcept; - void p_decrypt_aesni(const void *in, void *out) const noexcept; + void p_init_aesni(const uint8_t* key) noexcept; + void p_encrypt_aesni(const void* in, void* out) const noexcept; + void p_decrypt_aesni(const void* in, void* out) const noexcept; #endif #ifdef ZT_AES_NEON - void p_init_armneon_crypto(const uint8_t *key) noexcept; - void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept; - void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept; + void p_init_armneon_crypto(const uint8_t* key) noexcept; + void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept; + void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept; #endif }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/AES_aesni.cpp b/core/AES_aesni.cpp index f32d0fb98..801bfc99e 100644 --- a/core/AES_aesni.cpp +++ b/core/AES_aesni.cpp @@ -14,8 +14,8 @@ // AES for X64 AES-NI extensions (no 32-bit X86 support). Supports AVX2 and // AVX512 VAES for performance in excess of 10GiB/sec/core on newer chips. -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" #ifdef ZT_AES_AESNI @@ -32,25 +32,32 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) #endif -__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept +__m128i +p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept { - y = _mm_shuffle_epi8(y, s_sseSwapBytes); - __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); - __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); - __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); - __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); - t2 = _mm_xor_si128(t2, t3); - t3 = _mm_slli_si128(t2, 8); - t2 = _mm_srli_si128(t2, 8); - t1 = _mm_xor_si128(t1, t3); - t4 = _mm_xor_si128(t4, t2); - __m128i t5 = _mm_srli_epi32(t1, 31); - t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4)); - t4 = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)), _mm_srli_si128(t5, 12)); - t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25)); - t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12)); - t4 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)), _mm_srli_epi32(t1, 7)), _mm_srli_epi32(t1, 1)); - return _mm_shuffle_epi8(t4, s_sseSwapBytes); + y = _mm_shuffle_epi8(y, s_sseSwapBytes); + __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); + __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); + __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); + __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); + t2 = _mm_xor_si128(t2, t3); + t3 = _mm_slli_si128(t2, 8); + t2 = _mm_srli_si128(t2, 8); + t1 = _mm_xor_si128(t1, t3); + t4 = _mm_xor_si128(t4, t2); + __m128i t5 = _mm_srli_epi32(t1, 31); + t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4)); + t4 = _mm_or_si128( + _mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)), + _mm_srli_si128(t5, 12)); + t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25)); + t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12)); + t4 = _mm_xor_si128( + _mm_xor_si128( + _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)), + _mm_srli_epi32(t1, 7)), + _mm_srli_epi32(t1, 1)); + return _mm_shuffle_epi8(t4, s_sseSwapBytes); } /* Disable VAES stuff on compilers too old to compile these intrinsics, @@ -58,7 +65,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept * The performance gain can be significant but regular SSE is already so * fast it's highly unlikely to be a rate limiting factor except on massive * servers and network infrastructure stuff. */ -#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) +#if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) #define ZT_AES_VAES512 1 @@ -67,49 +74,53 @@ __attribute__((__target__("sse4,aes,avx,avx2,vaes,avx512f,avx512bw"))) #endif void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, const uint8_t *&in, uint8_t *&out, const __m128i *const k) noexcept { - const __m512i kk0 = _mm512_broadcast_i32x4(k[0]); - const __m512i kk1 = _mm512_broadcast_i32x4(k[1]); - const __m512i kk2 = _mm512_broadcast_i32x4(k[2]); - const __m512i kk3 = _mm512_broadcast_i32x4(k[3]); - const __m512i kk4 = _mm512_broadcast_i32x4(k[4]); - const __m512i kk5 = _mm512_broadcast_i32x4(k[5]); - const __m512i kk6 = _mm512_broadcast_i32x4(k[6]); - const __m512i kk7 = _mm512_broadcast_i32x4(k[7]); - const __m512i kk8 = _mm512_broadcast_i32x4(k[8]); - const __m512i kk9 = _mm512_broadcast_i32x4(k[9]); - const __m512i kk10 = _mm512_broadcast_i32x4(k[10]); - const __m512i kk11 = _mm512_broadcast_i32x4(k[11]); - const __m512i kk12 = _mm512_broadcast_i32x4(k[12]); - const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); - const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); - do { - __m512i p0 = _mm512_loadu_si512(reinterpret_cast(in)); - __m512i d0 = _mm512_set_epi64( - (long long)Utils::hton(c1 + 3ULL), (long long)c0, - (long long)Utils::hton(c1 + 2ULL), (long long)c0, - (long long)Utils::hton(c1 + 1ULL), (long long)c0, - (long long)Utils::hton(c1), (long long)c0); - c1 += 4; - in += 64; - len -= 64; - d0 = _mm512_xor_si512(d0, kk0); - d0 = _mm512_aesenc_epi128(d0, kk1); - d0 = _mm512_aesenc_epi128(d0, kk2); - d0 = _mm512_aesenc_epi128(d0, kk3); - d0 = _mm512_aesenc_epi128(d0, kk4); - d0 = _mm512_aesenc_epi128(d0, kk5); - d0 = _mm512_aesenc_epi128(d0, kk6); - d0 = _mm512_aesenc_epi128(d0, kk7); - d0 = _mm512_aesenc_epi128(d0, kk8); - d0 = _mm512_aesenc_epi128(d0, kk9); - d0 = _mm512_aesenc_epi128(d0, kk10); - d0 = _mm512_aesenc_epi128(d0, kk11); - d0 = _mm512_aesenc_epi128(d0, kk12); - d0 = _mm512_aesenc_epi128(d0, kk13); - d0 = _mm512_aesenclast_epi128(d0, kk14); - _mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0)); - out += 64; - } while (likely(len >= 64)); + const __m512i kk0 = _mm512_broadcast_i32x4(k[0]); + const __m512i kk1 = _mm512_broadcast_i32x4(k[1]); + const __m512i kk2 = _mm512_broadcast_i32x4(k[2]); + const __m512i kk3 = _mm512_broadcast_i32x4(k[3]); + const __m512i kk4 = _mm512_broadcast_i32x4(k[4]); + const __m512i kk5 = _mm512_broadcast_i32x4(k[5]); + const __m512i kk6 = _mm512_broadcast_i32x4(k[6]); + const __m512i kk7 = _mm512_broadcast_i32x4(k[7]); + const __m512i kk8 = _mm512_broadcast_i32x4(k[8]); + const __m512i kk9 = _mm512_broadcast_i32x4(k[9]); + const __m512i kk10 = _mm512_broadcast_i32x4(k[10]); + const __m512i kk11 = _mm512_broadcast_i32x4(k[11]); + const __m512i kk12 = _mm512_broadcast_i32x4(k[12]); + const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); + const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); + do { + __m512i p0 = _mm512_loadu_si512(reinterpret_cast(in)); + __m512i d0 = _mm512_set_epi64( + (long long)Utils::hton(c1 + 3ULL), + (long long)c0, + (long long)Utils::hton(c1 + 2ULL), + (long long)c0, + (long long)Utils::hton(c1 + 1ULL), + (long long)c0, + (long long)Utils::hton(c1), + (long long)c0); + c1 += 4; + in += 64; + len -= 64; + d0 = _mm512_xor_si512(d0, kk0); + d0 = _mm512_aesenc_epi128(d0, kk1); + d0 = _mm512_aesenc_epi128(d0, kk2); + d0 = _mm512_aesenc_epi128(d0, kk3); + d0 = _mm512_aesenc_epi128(d0, kk4); + d0 = _mm512_aesenc_epi128(d0, kk5); + d0 = _mm512_aesenc_epi128(d0, kk6); + d0 = _mm512_aesenc_epi128(d0, kk7); + d0 = _mm512_aesenc_epi128(d0, kk8); + d0 = _mm512_aesenc_epi128(d0, kk9); + d0 = _mm512_aesenc_epi128(d0, kk10); + d0 = _mm512_aesenc_epi128(d0, kk11); + d0 = _mm512_aesenc_epi128(d0, kk12); + d0 = _mm512_aesenc_epi128(d0, kk13); + d0 = _mm512_aesenclast_epi128(d0, kk14); + _mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0)); + out += 64; + } while (likely(len >= 64)); } #define ZT_AES_VAES256 1 @@ -119,174 +130,202 @@ __attribute__((__target__("sse4,aes,avx,avx2,vaes"))) #endif void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, const uint8_t *&in, uint8_t *&out, const __m128i *const k) noexcept { - const __m256i kk0 = _mm256_broadcastsi128_si256(k[0]); - const __m256i kk1 = _mm256_broadcastsi128_si256(k[1]); - const __m256i kk2 = _mm256_broadcastsi128_si256(k[2]); - const __m256i kk3 = _mm256_broadcastsi128_si256(k[3]); - const __m256i kk4 = _mm256_broadcastsi128_si256(k[4]); - const __m256i kk5 = _mm256_broadcastsi128_si256(k[5]); - const __m256i kk6 = _mm256_broadcastsi128_si256(k[6]); - const __m256i kk7 = _mm256_broadcastsi128_si256(k[7]); - const __m256i kk8 = _mm256_broadcastsi128_si256(k[8]); - const __m256i kk9 = _mm256_broadcastsi128_si256(k[9]); - const __m256i kk10 = _mm256_broadcastsi128_si256(k[10]); - const __m256i kk11 = _mm256_broadcastsi128_si256(k[11]); - const __m256i kk12 = _mm256_broadcastsi128_si256(k[12]); - const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); - const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); - do { - __m256i p0 = _mm256_loadu_si256(reinterpret_cast(in)); - __m256i p1 = _mm256_loadu_si256(reinterpret_cast(in + 32)); - __m256i d0 = _mm256_set_epi64x( - (long long)Utils::hton(c1 + 1ULL), (long long)c0, - (long long)Utils::hton(c1), (long long)c0); - __m256i d1 = _mm256_set_epi64x( - (long long)Utils::hton(c1 + 3ULL), (long long)c0, - (long long)Utils::hton(c1 + 2ULL), (long long)c0); - c1 += 4; - in += 64; - len -= 64; - d0 = _mm256_xor_si256(d0, kk0); - d1 = _mm256_xor_si256(d1, kk0); - d0 = _mm256_aesenc_epi128(d0, kk1); - d1 = _mm256_aesenc_epi128(d1, kk1); - d0 = _mm256_aesenc_epi128(d0, kk2); - d1 = _mm256_aesenc_epi128(d1, kk2); - d0 = _mm256_aesenc_epi128(d0, kk3); - d1 = _mm256_aesenc_epi128(d1, kk3); - d0 = _mm256_aesenc_epi128(d0, kk4); - d1 = _mm256_aesenc_epi128(d1, kk4); - d0 = _mm256_aesenc_epi128(d0, kk5); - d1 = _mm256_aesenc_epi128(d1, kk5); - d0 = _mm256_aesenc_epi128(d0, kk6); - d1 = _mm256_aesenc_epi128(d1, kk6); - d0 = _mm256_aesenc_epi128(d0, kk7); - d1 = _mm256_aesenc_epi128(d1, kk7); - d0 = _mm256_aesenc_epi128(d0, kk8); - d1 = _mm256_aesenc_epi128(d1, kk8); - d0 = _mm256_aesenc_epi128(d0, kk9); - d1 = _mm256_aesenc_epi128(d1, kk9); - d0 = _mm256_aesenc_epi128(d0, kk10); - d1 = _mm256_aesenc_epi128(d1, kk10); - d0 = _mm256_aesenc_epi128(d0, kk11); - d1 = _mm256_aesenc_epi128(d1, kk11); - d0 = _mm256_aesenc_epi128(d0, kk12); - d1 = _mm256_aesenc_epi128(d1, kk12); - d0 = _mm256_aesenc_epi128(d0, kk13); - d1 = _mm256_aesenc_epi128(d1, kk13); - d0 = _mm256_aesenclast_epi128(d0, kk14); - d1 = _mm256_aesenclast_epi128(d1, kk14); - _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0)); - _mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1)); - out += 64; - } while (likely(len >= 64)); + const __m256i kk0 = _mm256_broadcastsi128_si256(k[0]); + const __m256i kk1 = _mm256_broadcastsi128_si256(k[1]); + const __m256i kk2 = _mm256_broadcastsi128_si256(k[2]); + const __m256i kk3 = _mm256_broadcastsi128_si256(k[3]); + const __m256i kk4 = _mm256_broadcastsi128_si256(k[4]); + const __m256i kk5 = _mm256_broadcastsi128_si256(k[5]); + const __m256i kk6 = _mm256_broadcastsi128_si256(k[6]); + const __m256i kk7 = _mm256_broadcastsi128_si256(k[7]); + const __m256i kk8 = _mm256_broadcastsi128_si256(k[8]); + const __m256i kk9 = _mm256_broadcastsi128_si256(k[9]); + const __m256i kk10 = _mm256_broadcastsi128_si256(k[10]); + const __m256i kk11 = _mm256_broadcastsi128_si256(k[11]); + const __m256i kk12 = _mm256_broadcastsi128_si256(k[12]); + const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); + const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); + do { + __m256i p0 = _mm256_loadu_si256(reinterpret_cast(in)); + __m256i p1 = _mm256_loadu_si256(reinterpret_cast(in + 32)); + __m256i d0 = _mm256_set_epi64x( + (long long)Utils::hton(c1 + 1ULL), + (long long)c0, + (long long)Utils::hton(c1), + (long long)c0); + __m256i d1 = _mm256_set_epi64x( + (long long)Utils::hton(c1 + 3ULL), + (long long)c0, + (long long)Utils::hton(c1 + 2ULL), + (long long)c0); + c1 += 4; + in += 64; + len -= 64; + d0 = _mm256_xor_si256(d0, kk0); + d1 = _mm256_xor_si256(d1, kk0); + d0 = _mm256_aesenc_epi128(d0, kk1); + d1 = _mm256_aesenc_epi128(d1, kk1); + d0 = _mm256_aesenc_epi128(d0, kk2); + d1 = _mm256_aesenc_epi128(d1, kk2); + d0 = _mm256_aesenc_epi128(d0, kk3); + d1 = _mm256_aesenc_epi128(d1, kk3); + d0 = _mm256_aesenc_epi128(d0, kk4); + d1 = _mm256_aesenc_epi128(d1, kk4); + d0 = _mm256_aesenc_epi128(d0, kk5); + d1 = _mm256_aesenc_epi128(d1, kk5); + d0 = _mm256_aesenc_epi128(d0, kk6); + d1 = _mm256_aesenc_epi128(d1, kk6); + d0 = _mm256_aesenc_epi128(d0, kk7); + d1 = _mm256_aesenc_epi128(d1, kk7); + d0 = _mm256_aesenc_epi128(d0, kk8); + d1 = _mm256_aesenc_epi128(d1, kk8); + d0 = _mm256_aesenc_epi128(d0, kk9); + d1 = _mm256_aesenc_epi128(d1, kk9); + d0 = _mm256_aesenc_epi128(d0, kk10); + d1 = _mm256_aesenc_epi128(d1, kk10); + d0 = _mm256_aesenc_epi128(d0, kk11); + d1 = _mm256_aesenc_epi128(d1, kk11); + d0 = _mm256_aesenc_epi128(d0, kk12); + d1 = _mm256_aesenc_epi128(d1, kk12); + d0 = _mm256_aesenc_epi128(d0, kk13); + d1 = _mm256_aesenc_epi128(d1, kk13); + d0 = _mm256_aesenclast_epi128(d0, kk14); + d1 = _mm256_aesenclast_epi128(d1, kk14); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0)); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1)); + out += 64; + } while (likely(len >= 64)); } -#endif // does compiler support AVX2 and AVX512 AES intrinsics? +#endif // does compiler support AVX2 and AVX512 AES intrinsics? #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif -__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept +__m128i +p_init256_1_aesni(__m128i a, __m128i b) noexcept { - __m128i x, y; - b = _mm_shuffle_epi32(b, 0xff); - y = _mm_slli_si128(a, 0x04); - x = _mm_xor_si128(a, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - x = _mm_xor_si128(x, b); - return x; + __m128i x, y; + b = _mm_shuffle_epi32(b, 0xff); + y = _mm_slli_si128(a, 0x04); + x = _mm_xor_si128(a, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + x = _mm_xor_si128(x, b); + return x; } #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif -__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept +__m128i +p_init256_2_aesni(__m128i a, __m128i b) noexcept { - __m128i x, y, z; - y = _mm_aeskeygenassist_si128(a, 0x00); - z = _mm_shuffle_epi32(y, 0xaa); - y = _mm_slli_si128(b, 0x04); - x = _mm_xor_si128(b, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - x = _mm_xor_si128(x, z); - return x; + __m128i x, y, z; + y = _mm_aeskeygenassist_si128(a, 0x00); + z = _mm_shuffle_epi32(y, 0xaa); + y = _mm_slli_si128(b, 0x04); + x = _mm_xor_si128(b, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + x = _mm_xor_si128(x, z); + return x; } -} // anonymous namespace +} // anonymous namespace #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) #endif void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept { - __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); + __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); - // Handle anything left over from a previous run that wasn't a multiple of 16 bytes. - if (_rp) { - for (;;) { - if (!len) - return; - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); - break; - } - } - } + // Handle anything left over from a previous run that wasn't a multiple of 16 bytes. + if (_rp) { + for (;;) { + if (! len) + return; + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y = p_gmacPCLMUL128( + _aes.p_k.ni.h[0], + _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r)))); + break; + } + } + } - if (likely(len >= 64)) { - const __m128i sb = s_sseSwapBytes; - const __m128i h = _aes.p_k.ni.h[0]; - const __m128i hh = _aes.p_k.ni.h[1]; - const __m128i hhh = _aes.p_k.ni.h[2]; - const __m128i hhhh = _aes.p_k.ni.h[3]; - const __m128i h2 = _aes.p_k.ni.h2[0]; - const __m128i hh2 = _aes.p_k.ni.h2[1]; - const __m128i hhh2 = _aes.p_k.ni.h2[2]; - const __m128i hhhh2 = _aes.p_k.ni.h2[3]; - const uint8_t *const end64 = in + (len & ~((unsigned int)63)); - len &= 63U; - do { - __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in))), sb); - __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 16)), sb); - __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 32)), sb); - __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 48)), sb); - in += 64; - __m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); - __m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); - __m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b)); - a = _mm_xor_si128(_mm_slli_si128(c, 8), a); - b = _mm_xor_si128(_mm_srli_si128(c, 8), b); - c = _mm_srli_epi32(a, 31); - a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4)); - b = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)), _mm_srli_si128(c, 12)); - c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25))); - a = _mm_xor_si128(a, _mm_slli_si128(c, 12)); - b = _mm_xor_si128(b, _mm_xor_si128(a, _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)), _mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7))))); - y = _mm_shuffle_epi8(b, sb); - } while (likely(in != end64)); - } + if (likely(len >= 64)) { + const __m128i sb = s_sseSwapBytes; + const __m128i h = _aes.p_k.ni.h[0]; + const __m128i hh = _aes.p_k.ni.h[1]; + const __m128i hhh = _aes.p_k.ni.h[2]; + const __m128i hhhh = _aes.p_k.ni.h[3]; + const __m128i h2 = _aes.p_k.ni.h2[0]; + const __m128i hh2 = _aes.p_k.ni.h2[1]; + const __m128i hhh2 = _aes.p_k.ni.h2[2]; + const __m128i hhhh2 = _aes.p_k.ni.h2[3]; + const uint8_t* const end64 = in + (len & ~((unsigned int)63)); + len &= 63U; + do { + __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in))), sb); + __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 16)), sb); + __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 32)), sb); + __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 48)), sb); + in += 64; + __m128i a = _mm_xor_si128( + _mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), + _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); + __m128i b = _mm_xor_si128( + _mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), + _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); + __m128i c = _mm_xor_si128( + _mm_xor_si128( + _mm_xor_si128( + _mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), + _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), + _mm_xor_si128( + _mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), + _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), + _mm_xor_si128(a, b)); + a = _mm_xor_si128(_mm_slli_si128(c, 8), a); + b = _mm_xor_si128(_mm_srli_si128(c, 8), b); + c = _mm_srli_epi32(a, 31); + a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4)); + b = _mm_or_si128( + _mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)), + _mm_srli_si128(c, 12)); + c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25))); + a = _mm_xor_si128(a, _mm_slli_si128(c, 12)); + b = _mm_xor_si128( + b, + _mm_xor_si128( + a, + _mm_xor_si128( + _mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)), + _mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7))))); + y = _mm_shuffle_epi8(b, sb); + } while (likely(in != end64)); + } - while (len >= 16) { - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in)))); - in += 16; - len -= 16; - } + while (len >= 16) { + y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in)))); + in += 16; + len -= 16; + } - _mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y); + _mm_storeu_si128(reinterpret_cast<__m128i*>(_y), y); - // Any overflow is cached for a later run or finish(). - for (unsigned int i = 0; i < len; ++i) - _r[i] = in[i]; - _rp = len; // len is always less than 16 here + // Any overflow is cached for a later run or finish(). + for (unsigned int i = 0; i < len; ++i) + _r[i] = in[i]; + _rp = len; // len is always less than 16 here } #ifdef __GNUC__ @@ -294,72 +333,72 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes"))) #endif void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept { - __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); + __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); - // Handle any remaining bytes, padding the last block with zeroes. - if (_rp) { - while (_rp < 16) - _r[_rp++] = 0; - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); - } + // Handle any remaining bytes, padding the last block with zeroes. + if (_rp) { + while (_rp < 16) + _r[_rp++] = 0; + y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r)))); + } - // Interleave encryption of IV with the final GHASH of y XOR (length * 8). - // Then XOR these together to get the final tag. - const __m128i *const k = _aes.p_k.ni.k; - const __m128i h = _aes.p_k.ni.h[0]; - y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); - y = _mm_shuffle_epi8(y, s_sseSwapBytes); - __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(_iv)), k[0]); - __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); - __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); - __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); - __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); - encIV = _mm_aesenc_si128(encIV, k[1]); - t2 = _mm_xor_si128(t2, t3); - t3 = _mm_slli_si128(t2, 8); - encIV = _mm_aesenc_si128(encIV, k[2]); - t2 = _mm_srli_si128(t2, 8); - t1 = _mm_xor_si128(t1, t3); - encIV = _mm_aesenc_si128(encIV, k[3]); - t4 = _mm_xor_si128(t4, t2); - __m128i t5 = _mm_srli_epi32(t1, 31); - t1 = _mm_slli_epi32(t1, 1); - __m128i t6 = _mm_srli_epi32(t4, 31); - encIV = _mm_aesenc_si128(encIV, k[4]); - t4 = _mm_slli_epi32(t4, 1); - t3 = _mm_srli_si128(t5, 12); - encIV = _mm_aesenc_si128(encIV, k[5]); - t6 = _mm_slli_si128(t6, 4); - t5 = _mm_slli_si128(t5, 4); - encIV = _mm_aesenc_si128(encIV, k[6]); - t1 = _mm_or_si128(t1, t5); - t4 = _mm_or_si128(t4, t6); - encIV = _mm_aesenc_si128(encIV, k[7]); - t4 = _mm_or_si128(t4, t3); - t5 = _mm_slli_epi32(t1, 31); - encIV = _mm_aesenc_si128(encIV, k[8]); - t6 = _mm_slli_epi32(t1, 30); - t3 = _mm_slli_epi32(t1, 25); - encIV = _mm_aesenc_si128(encIV, k[9]); - t5 = _mm_xor_si128(t5, t6); - t5 = _mm_xor_si128(t5, t3); - encIV = _mm_aesenc_si128(encIV, k[10]); - t6 = _mm_srli_si128(t5, 4); - t4 = _mm_xor_si128(t4, t6); - encIV = _mm_aesenc_si128(encIV, k[11]); - t5 = _mm_slli_si128(t5, 12); - t1 = _mm_xor_si128(t1, t5); - t4 = _mm_xor_si128(t4, t1); - t5 = _mm_srli_epi32(t1, 1); - encIV = _mm_aesenc_si128(encIV, k[12]); - t2 = _mm_srli_epi32(t1, 2); - t3 = _mm_srli_epi32(t1, 7); - encIV = _mm_aesenc_si128(encIV, k[13]); - t4 = _mm_xor_si128(t4, t2); - t4 = _mm_xor_si128(t4, t3); - encIV = _mm_aesenclast_si128(encIV, k[14]); - t4 = _mm_xor_si128(t4, t5); - _mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); + // Interleave encryption of IV with the final GHASH of y XOR (length * 8). + // Then XOR these together to get the final tag. + const __m128i* const k = _aes.p_k.ni.k; + const __m128i h = _aes.p_k.ni.h[0]; + y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); + y = _mm_shuffle_epi8(y, s_sseSwapBytes); + __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(_iv)), k[0]); + __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); + __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); + __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); + __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); + encIV = _mm_aesenc_si128(encIV, k[1]); + t2 = _mm_xor_si128(t2, t3); + t3 = _mm_slli_si128(t2, 8); + encIV = _mm_aesenc_si128(encIV, k[2]); + t2 = _mm_srli_si128(t2, 8); + t1 = _mm_xor_si128(t1, t3); + encIV = _mm_aesenc_si128(encIV, k[3]); + t4 = _mm_xor_si128(t4, t2); + __m128i t5 = _mm_srli_epi32(t1, 31); + t1 = _mm_slli_epi32(t1, 1); + __m128i t6 = _mm_srli_epi32(t4, 31); + encIV = _mm_aesenc_si128(encIV, k[4]); + t4 = _mm_slli_epi32(t4, 1); + t3 = _mm_srli_si128(t5, 12); + encIV = _mm_aesenc_si128(encIV, k[5]); + t6 = _mm_slli_si128(t6, 4); + t5 = _mm_slli_si128(t5, 4); + encIV = _mm_aesenc_si128(encIV, k[6]); + t1 = _mm_or_si128(t1, t5); + t4 = _mm_or_si128(t4, t6); + encIV = _mm_aesenc_si128(encIV, k[7]); + t4 = _mm_or_si128(t4, t3); + t5 = _mm_slli_epi32(t1, 31); + encIV = _mm_aesenc_si128(encIV, k[8]); + t6 = _mm_slli_epi32(t1, 30); + t3 = _mm_slli_epi32(t1, 25); + encIV = _mm_aesenc_si128(encIV, k[9]); + t5 = _mm_xor_si128(t5, t6); + t5 = _mm_xor_si128(t5, t3); + encIV = _mm_aesenc_si128(encIV, k[10]); + t6 = _mm_srli_si128(t5, 4); + t4 = _mm_xor_si128(t4, t6); + encIV = _mm_aesenc_si128(encIV, k[11]); + t5 = _mm_slli_si128(t5, 12); + t1 = _mm_xor_si128(t1, t5); + t4 = _mm_xor_si128(t4, t1); + t5 = _mm_srli_epi32(t1, 1); + encIV = _mm_aesenc_si128(encIV, k[12]); + t2 = _mm_srli_epi32(t1, 2); + t3 = _mm_srli_epi32(t1, 7); + encIV = _mm_aesenc_si128(encIV, k[13]); + t4 = _mm_xor_si128(t4, t2); + t4 = _mm_xor_si128(t4, t3); + encIV = _mm_aesenclast_si128(encIV, k[14]); + t4 = _mm_xor_si128(t4, t5); + _mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); } #ifdef __GNUC__ @@ -367,198 +406,205 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes"))) #endif void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept { - const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); - uint64_t c1 = Utils::ntoh(_ctr[1]); + const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); + uint64_t c1 = Utils::ntoh(_ctr[1]); - const __m128i *const k = _aes.p_k.ni.k; - const __m128i k0 = k[0]; - const __m128i k1 = k[1]; - const __m128i k2 = k[2]; - const __m128i k3 = k[3]; - const __m128i k4 = k[4]; - const __m128i k5 = k[5]; - const __m128i k6 = k[6]; - const __m128i k7 = k[7]; - const __m128i k8 = k[8]; - const __m128i k9 = k[9]; - const __m128i k10 = k[10]; - const __m128i k11 = k[11]; - const __m128i k12 = k[12]; - const __m128i k13 = k[13]; - const __m128i k14 = k[14]; + const __m128i* const k = _aes.p_k.ni.k; + const __m128i k0 = k[0]; + const __m128i k1 = k[1]; + const __m128i k2 = k[2]; + const __m128i k3 = k[3]; + const __m128i k4 = k[4]; + const __m128i k5 = k[5]; + const __m128i k6 = k[6]; + const __m128i k7 = k[7]; + const __m128i k8 = k[8]; + const __m128i k9 = k[9]; + const __m128i k10 = k[10]; + const __m128i k11 = k[11]; + const __m128i k12 = k[12]; + const __m128i k13 = k[13]; + const __m128i k14 = k[14]; - // Complete any unfinished blocks from previous calls to crypt(). - unsigned int totalLen = _len; - if ((totalLen & 15U)) { - for (;;) { - if (unlikely(!len)) { - _ctr[1] = Utils::hton(c1); - _len = totalLen; - return; - } - --len; - out[totalLen++] = *(in++); - if (!(totalLen & 15U)) { - __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); - d0 = _mm_xor_si128(d0, k0); - d0 = _mm_aesenc_si128(d0, k1); - d0 = _mm_aesenc_si128(d0, k2); - d0 = _mm_aesenc_si128(d0, k3); - d0 = _mm_aesenc_si128(d0, k4); - d0 = _mm_aesenc_si128(d0, k5); - d0 = _mm_aesenc_si128(d0, k6); - d0 = _mm_aesenc_si128(d0, k7); - d0 = _mm_aesenc_si128(d0, k8); - d0 = _mm_aesenc_si128(d0, k9); - d0 = _mm_aesenc_si128(d0, k10); - __m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16)); - d0 = _mm_aesenc_si128(d0, k11); - const __m128i p0 = _mm_loadu_si128(outblk); - d0 = _mm_aesenc_si128(d0, k12); - d0 = _mm_aesenc_si128(d0, k13); - d0 = _mm_aesenclast_si128(d0, k14); - _mm_storeu_si128(outblk, _mm_xor_si128(p0, d0)); - break; - } - } - } + // Complete any unfinished blocks from previous calls to crypt(). + unsigned int totalLen = _len; + if ((totalLen & 15U)) { + for (;;) { + if (unlikely(! len)) { + _ctr[1] = Utils::hton(c1); + _len = totalLen; + return; + } + --len; + out[totalLen++] = *(in++); + if (! (totalLen & 15U)) { + __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); + d0 = _mm_xor_si128(d0, k0); + d0 = _mm_aesenc_si128(d0, k1); + d0 = _mm_aesenc_si128(d0, k2); + d0 = _mm_aesenc_si128(d0, k3); + d0 = _mm_aesenc_si128(d0, k4); + d0 = _mm_aesenc_si128(d0, k5); + d0 = _mm_aesenc_si128(d0, k6); + d0 = _mm_aesenc_si128(d0, k7); + d0 = _mm_aesenc_si128(d0, k8); + d0 = _mm_aesenc_si128(d0, k9); + d0 = _mm_aesenc_si128(d0, k10); + __m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16)); + d0 = _mm_aesenc_si128(d0, k11); + const __m128i p0 = _mm_loadu_si128(outblk); + d0 = _mm_aesenc_si128(d0, k12); + d0 = _mm_aesenc_si128(d0, k13); + d0 = _mm_aesenclast_si128(d0, k14); + _mm_storeu_si128(outblk, _mm_xor_si128(p0, d0)); + break; + } + } + } - out += totalLen; - _len = totalLen + len; - - if (likely(len >= 64)) { + out += totalLen; + _len = totalLen + len; + if (likely(len >= 64)) { #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) - if (Utils::CPUID.vaes) { - if (Utils::CPUID.avx512f) { - p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); - } else { - p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); - } - goto skip_conventional_aesni_64; - } + if (Utils::CPUID.vaes) { + if (Utils::CPUID.avx512f) { + p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); + } + else { + p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); + } + goto skip_conventional_aesni_64; + } #endif -#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) - if (Utils::CPUID.vaes && (len >= 256)) { - p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); - goto skip_conventional_aesni_64; - } +#if ! defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) + if (Utils::CPUID.vaes && (len >= 256)) { + p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); + goto skip_conventional_aesni_64; + } #endif - const uint8_t *const eof64 = in + (len & ~((unsigned int)63)); - len &= 63; - __m128i d0, d1, d2, d3; - do { - const uint64_t c10 = Utils::hton(c1); - const uint64_t c11 = Utils::hton(c1 + 1ULL); - const uint64_t c12 = Utils::hton(c1 + 2ULL); - const uint64_t c13 = Utils::hton(c1 + 3ULL); - d0 = _mm_insert_epi64(dd, (long long)c10, 1); - d1 = _mm_insert_epi64(dd, (long long)c11, 1); - d2 = _mm_insert_epi64(dd, (long long)c12, 1); - d3 = _mm_insert_epi64(dd, (long long)c13, 1); - c1 += 4; - d0 = _mm_xor_si128(d0, k0); - d1 = _mm_xor_si128(d1, k0); - d2 = _mm_xor_si128(d2, k0); - d3 = _mm_xor_si128(d3, k0); - d0 = _mm_aesenc_si128(d0, k1); - d1 = _mm_aesenc_si128(d1, k1); - d2 = _mm_aesenc_si128(d2, k1); - d3 = _mm_aesenc_si128(d3, k1); - d0 = _mm_aesenc_si128(d0, k2); - d1 = _mm_aesenc_si128(d1, k2); - d2 = _mm_aesenc_si128(d2, k2); - d3 = _mm_aesenc_si128(d3, k2); - d0 = _mm_aesenc_si128(d0, k3); - d1 = _mm_aesenc_si128(d1, k3); - d2 = _mm_aesenc_si128(d2, k3); - d3 = _mm_aesenc_si128(d3, k3); - d0 = _mm_aesenc_si128(d0, k4); - d1 = _mm_aesenc_si128(d1, k4); - d2 = _mm_aesenc_si128(d2, k4); - d3 = _mm_aesenc_si128(d3, k4); - d0 = _mm_aesenc_si128(d0, k5); - d1 = _mm_aesenc_si128(d1, k5); - d2 = _mm_aesenc_si128(d2, k5); - d3 = _mm_aesenc_si128(d3, k5); - d0 = _mm_aesenc_si128(d0, k6); - d1 = _mm_aesenc_si128(d1, k6); - d2 = _mm_aesenc_si128(d2, k6); - d3 = _mm_aesenc_si128(d3, k6); - d0 = _mm_aesenc_si128(d0, k7); - d1 = _mm_aesenc_si128(d1, k7); - d2 = _mm_aesenc_si128(d2, k7); - d3 = _mm_aesenc_si128(d3, k7); - d0 = _mm_aesenc_si128(d0, k8); - d1 = _mm_aesenc_si128(d1, k8); - d2 = _mm_aesenc_si128(d2, k8); - d3 = _mm_aesenc_si128(d3, k8); - d0 = _mm_aesenc_si128(d0, k9); - d1 = _mm_aesenc_si128(d1, k9); - d2 = _mm_aesenc_si128(d2, k9); - d3 = _mm_aesenc_si128(d3, k9); - d0 = _mm_aesenc_si128(d0, k10); - d1 = _mm_aesenc_si128(d1, k10); - d2 = _mm_aesenc_si128(d2, k10); - d3 = _mm_aesenc_si128(d3, k10); - d0 = _mm_aesenc_si128(d0, k11); - d1 = _mm_aesenc_si128(d1, k11); - d2 = _mm_aesenc_si128(d2, k11); - d3 = _mm_aesenc_si128(d3, k11); - d0 = _mm_aesenc_si128(d0, k12); - d1 = _mm_aesenc_si128(d1, k12); - d2 = _mm_aesenc_si128(d2, k12); - d3 = _mm_aesenc_si128(d3, k12); - d0 = _mm_aesenc_si128(d0, k13); - d1 = _mm_aesenc_si128(d1, k13); - d2 = _mm_aesenc_si128(d2, k13); - d3 = _mm_aesenc_si128(d3, k13); - d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in))); - d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast(in + 16))); - d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast(in + 32))); - d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast(in + 48))); - in += 64; - _mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3); - out += 64; - } while (likely(in != eof64)); + const uint8_t* const eof64 = in + (len & ~((unsigned int)63)); + len &= 63; + __m128i d0, d1, d2, d3; + do { + const uint64_t c10 = Utils::hton(c1); + const uint64_t c11 = Utils::hton(c1 + 1ULL); + const uint64_t c12 = Utils::hton(c1 + 2ULL); + const uint64_t c13 = Utils::hton(c1 + 3ULL); + d0 = _mm_insert_epi64(dd, (long long)c10, 1); + d1 = _mm_insert_epi64(dd, (long long)c11, 1); + d2 = _mm_insert_epi64(dd, (long long)c12, 1); + d3 = _mm_insert_epi64(dd, (long long)c13, 1); + c1 += 4; + d0 = _mm_xor_si128(d0, k0); + d1 = _mm_xor_si128(d1, k0); + d2 = _mm_xor_si128(d2, k0); + d3 = _mm_xor_si128(d3, k0); + d0 = _mm_aesenc_si128(d0, k1); + d1 = _mm_aesenc_si128(d1, k1); + d2 = _mm_aesenc_si128(d2, k1); + d3 = _mm_aesenc_si128(d3, k1); + d0 = _mm_aesenc_si128(d0, k2); + d1 = _mm_aesenc_si128(d1, k2); + d2 = _mm_aesenc_si128(d2, k2); + d3 = _mm_aesenc_si128(d3, k2); + d0 = _mm_aesenc_si128(d0, k3); + d1 = _mm_aesenc_si128(d1, k3); + d2 = _mm_aesenc_si128(d2, k3); + d3 = _mm_aesenc_si128(d3, k3); + d0 = _mm_aesenc_si128(d0, k4); + d1 = _mm_aesenc_si128(d1, k4); + d2 = _mm_aesenc_si128(d2, k4); + d3 = _mm_aesenc_si128(d3, k4); + d0 = _mm_aesenc_si128(d0, k5); + d1 = _mm_aesenc_si128(d1, k5); + d2 = _mm_aesenc_si128(d2, k5); + d3 = _mm_aesenc_si128(d3, k5); + d0 = _mm_aesenc_si128(d0, k6); + d1 = _mm_aesenc_si128(d1, k6); + d2 = _mm_aesenc_si128(d2, k6); + d3 = _mm_aesenc_si128(d3, k6); + d0 = _mm_aesenc_si128(d0, k7); + d1 = _mm_aesenc_si128(d1, k7); + d2 = _mm_aesenc_si128(d2, k7); + d3 = _mm_aesenc_si128(d3, k7); + d0 = _mm_aesenc_si128(d0, k8); + d1 = _mm_aesenc_si128(d1, k8); + d2 = _mm_aesenc_si128(d2, k8); + d3 = _mm_aesenc_si128(d3, k8); + d0 = _mm_aesenc_si128(d0, k9); + d1 = _mm_aesenc_si128(d1, k9); + d2 = _mm_aesenc_si128(d2, k9); + d3 = _mm_aesenc_si128(d3, k9); + d0 = _mm_aesenc_si128(d0, k10); + d1 = _mm_aesenc_si128(d1, k10); + d2 = _mm_aesenc_si128(d2, k10); + d3 = _mm_aesenc_si128(d3, k10); + d0 = _mm_aesenc_si128(d0, k11); + d1 = _mm_aesenc_si128(d1, k11); + d2 = _mm_aesenc_si128(d2, k11); + d3 = _mm_aesenc_si128(d3, k11); + d0 = _mm_aesenc_si128(d0, k12); + d1 = _mm_aesenc_si128(d1, k12); + d2 = _mm_aesenc_si128(d2, k12); + d3 = _mm_aesenc_si128(d3, k12); + d0 = _mm_aesenc_si128(d0, k13); + d1 = _mm_aesenc_si128(d1, k13); + d2 = _mm_aesenc_si128(d2, k13); + d3 = _mm_aesenc_si128(d3, k13); + d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in))); + d1 = _mm_xor_si128( + _mm_aesenclast_si128(d1, k14), + _mm_loadu_si128(reinterpret_cast(in + 16))); + d2 = _mm_xor_si128( + _mm_aesenclast_si128(d2, k14), + _mm_loadu_si128(reinterpret_cast(in + 32))); + d3 = _mm_xor_si128( + _mm_aesenclast_si128(d3, k14), + _mm_loadu_si128(reinterpret_cast(in + 48))); + in += 64; + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3); + out += 64; + } while (likely(in != eof64)); + } - } +skip_conventional_aesni_64: + while (len >= 16) { + __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); + d0 = _mm_xor_si128(d0, k0); + d0 = _mm_aesenc_si128(d0, k1); + d0 = _mm_aesenc_si128(d0, k2); + d0 = _mm_aesenc_si128(d0, k3); + d0 = _mm_aesenc_si128(d0, k4); + d0 = _mm_aesenc_si128(d0, k5); + d0 = _mm_aesenc_si128(d0, k6); + d0 = _mm_aesenc_si128(d0, k7); + d0 = _mm_aesenc_si128(d0, k8); + d0 = _mm_aesenc_si128(d0, k9); + d0 = _mm_aesenc_si128(d0, k10); + d0 = _mm_aesenc_si128(d0, k11); + d0 = _mm_aesenc_si128(d0, k12); + d0 = _mm_aesenc_si128(d0, k13); + _mm_storeu_si128( + reinterpret_cast<__m128i*>(out), + _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in)))); + in += 16; + len -= 16; + out += 16; + } - skip_conventional_aesni_64: - while (len >= 16) { - __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); - d0 = _mm_xor_si128(d0, k0); - d0 = _mm_aesenc_si128(d0, k1); - d0 = _mm_aesenc_si128(d0, k2); - d0 = _mm_aesenc_si128(d0, k3); - d0 = _mm_aesenc_si128(d0, k4); - d0 = _mm_aesenc_si128(d0, k5); - d0 = _mm_aesenc_si128(d0, k6); - d0 = _mm_aesenc_si128(d0, k7); - d0 = _mm_aesenc_si128(d0, k8); - d0 = _mm_aesenc_si128(d0, k9); - d0 = _mm_aesenc_si128(d0, k10); - d0 = _mm_aesenc_si128(d0, k11); - d0 = _mm_aesenc_si128(d0, k12); - d0 = _mm_aesenc_si128(d0, k13); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in)))); - in += 16; - len -= 16; - out += 16; - } + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + for (unsigned int i = 0; i < len; ++i) + out[i] = in[i]; - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - for (unsigned int i = 0; i < len; ++i) - out[i] = in[i]; - - _ctr[1] = Utils::hton(c1); + _ctr[1] = Utils::hton(c1); } #ifdef __GNUC__ @@ -566,63 +612,63 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_init_aesni(const uint8_t *key) noexcept { - __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; - p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key); - p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16)); - p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); - p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); - p_k.ni.k[5] = k5 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[6] = k6 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x04)); - p_k.ni.k[7] = k7 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[8] = k8 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x08)); - p_k.ni.k[9] = k9 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[10] = k10 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x10)); - p_k.ni.k[11] = k11 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[12] = k12 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x20)); - p_k.ni.k[13] = k13 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[14] = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x40)); - p_k.ni.k[15] = _mm_aesimc_si128(k13); - p_k.ni.k[16] = _mm_aesimc_si128(k12); - p_k.ni.k[17] = _mm_aesimc_si128(k11); - p_k.ni.k[18] = _mm_aesimc_si128(k10); - p_k.ni.k[19] = _mm_aesimc_si128(k9); - p_k.ni.k[20] = _mm_aesimc_si128(k8); - p_k.ni.k[21] = _mm_aesimc_si128(k7); - p_k.ni.k[22] = _mm_aesimc_si128(k6); - p_k.ni.k[23] = _mm_aesimc_si128(k5); - p_k.ni.k[24] = _mm_aesimc_si128(k4); - p_k.ni.k[25] = _mm_aesimc_si128(k3); - p_k.ni.k[26] = _mm_aesimc_si128(k2); - p_k.ni.k[27] = _mm_aesimc_si128(k1); + __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; + p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key); + p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16)); + p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); + p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); + p_k.ni.k[5] = k5 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[6] = k6 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x04)); + p_k.ni.k[7] = k7 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[8] = k8 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x08)); + p_k.ni.k[9] = k9 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[10] = k10 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x10)); + p_k.ni.k[11] = k11 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[12] = k12 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x20)); + p_k.ni.k[13] = k13 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[14] = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x40)); + p_k.ni.k[15] = _mm_aesimc_si128(k13); + p_k.ni.k[16] = _mm_aesimc_si128(k12); + p_k.ni.k[17] = _mm_aesimc_si128(k11); + p_k.ni.k[18] = _mm_aesimc_si128(k10); + p_k.ni.k[19] = _mm_aesimc_si128(k9); + p_k.ni.k[20] = _mm_aesimc_si128(k8); + p_k.ni.k[21] = _mm_aesimc_si128(k7); + p_k.ni.k[22] = _mm_aesimc_si128(k6); + p_k.ni.k[23] = _mm_aesimc_si128(k5); + p_k.ni.k[24] = _mm_aesimc_si128(k4); + p_k.ni.k[25] = _mm_aesimc_si128(k3); + p_k.ni.k[26] = _mm_aesimc_si128(k2); + p_k.ni.k[27] = _mm_aesimc_si128(k1); - __m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]); - h = _mm_aesenc_si128(h, k1); - h = _mm_aesenc_si128(h, k2); - h = _mm_aesenc_si128(h, k3); - h = _mm_aesenc_si128(h, k4); - h = _mm_aesenc_si128(h, k5); - h = _mm_aesenc_si128(h, k6); - h = _mm_aesenc_si128(h, k7); - h = _mm_aesenc_si128(h, k8); - h = _mm_aesenc_si128(h, k9); - h = _mm_aesenc_si128(h, k10); - h = _mm_aesenc_si128(h, k11); - h = _mm_aesenc_si128(h, k12); - h = _mm_aesenc_si128(h, k13); - h = _mm_aesenclast_si128(h, p_k.ni.k[14]); - __m128i hswap = _mm_shuffle_epi8(h, s_sseSwapBytes); - __m128i hh = p_gmacPCLMUL128(hswap, h); - __m128i hhh = p_gmacPCLMUL128(hswap, hh); - __m128i hhhh = p_gmacPCLMUL128(hswap, hhh); - p_k.ni.h[0] = hswap; - p_k.ni.h[1] = hh = _mm_shuffle_epi8(hh, s_sseSwapBytes); - p_k.ni.h[2] = hhh = _mm_shuffle_epi8(hhh, s_sseSwapBytes); - p_k.ni.h[3] = hhhh = _mm_shuffle_epi8(hhhh, s_sseSwapBytes); - p_k.ni.h2[0] = _mm_xor_si128(_mm_shuffle_epi32(hswap, 78), hswap); - p_k.ni.h2[1] = _mm_xor_si128(_mm_shuffle_epi32(hh, 78), hh); - p_k.ni.h2[2] = _mm_xor_si128(_mm_shuffle_epi32(hhh, 78), hhh); - p_k.ni.h2[3] = _mm_xor_si128(_mm_shuffle_epi32(hhhh, 78), hhhh); + __m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]); + h = _mm_aesenc_si128(h, k1); + h = _mm_aesenc_si128(h, k2); + h = _mm_aesenc_si128(h, k3); + h = _mm_aesenc_si128(h, k4); + h = _mm_aesenc_si128(h, k5); + h = _mm_aesenc_si128(h, k6); + h = _mm_aesenc_si128(h, k7); + h = _mm_aesenc_si128(h, k8); + h = _mm_aesenc_si128(h, k9); + h = _mm_aesenc_si128(h, k10); + h = _mm_aesenc_si128(h, k11); + h = _mm_aesenc_si128(h, k12); + h = _mm_aesenc_si128(h, k13); + h = _mm_aesenclast_si128(h, p_k.ni.k[14]); + __m128i hswap = _mm_shuffle_epi8(h, s_sseSwapBytes); + __m128i hh = p_gmacPCLMUL128(hswap, h); + __m128i hhh = p_gmacPCLMUL128(hswap, hh); + __m128i hhhh = p_gmacPCLMUL128(hswap, hhh); + p_k.ni.h[0] = hswap; + p_k.ni.h[1] = hh = _mm_shuffle_epi8(hh, s_sseSwapBytes); + p_k.ni.h[2] = hhh = _mm_shuffle_epi8(hhh, s_sseSwapBytes); + p_k.ni.h[3] = hhhh = _mm_shuffle_epi8(hhhh, s_sseSwapBytes); + p_k.ni.h2[0] = _mm_xor_si128(_mm_shuffle_epi32(hswap, 78), hswap); + p_k.ni.h2[1] = _mm_xor_si128(_mm_shuffle_epi32(hh, 78), hh); + p_k.ni.h2[2] = _mm_xor_si128(_mm_shuffle_epi32(hhh, 78), hhh); + p_k.ni.h2[3] = _mm_xor_si128(_mm_shuffle_epi32(hhhh, 78), hhhh); } #ifdef __GNUC__ @@ -630,22 +676,22 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept { - __m128i tmp = _mm_loadu_si128((const __m128i *)in); - tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[3]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[4]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[5]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[6]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[7]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[8]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[9]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[10]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); - _mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); + __m128i tmp = _mm_loadu_si128((const __m128i*)in); + tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[3]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[4]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[5]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[6]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[7]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[8]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[9]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[10]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); + _mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); } #ifdef __GNUC__ @@ -653,24 +699,24 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_decrypt_aesni(const void *in, void *out) const noexcept { - __m128i tmp = _mm_loadu_si128((const __m128i *)in); - tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[17]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[18]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[19]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[20]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[21]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[22]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[23]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[24]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); - _mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); + __m128i tmp = _mm_loadu_si128((const __m128i*)in); + tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[17]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[18]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[19]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[20]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[21]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[22]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[23]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[24]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); + _mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_AES_AESNI +#endif // ZT_AES_AESNI diff --git a/core/AES_armcrypto.cpp b/core/AES_armcrypto.cpp index 39628c08c..3c9d2a770 100644 --- a/core/AES_armcrypto.cpp +++ b/core/AES_armcrypto.cpp @@ -13,8 +13,8 @@ // AES for ARM crypto extensions and NEON. -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" #ifdef ZT_AES_NEON @@ -24,366 +24,386 @@ namespace { ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const uint8_t b[16]) noexcept { - uint8x16_t r0, r1, t0, t1; - r0 = vld1q_u8(b); - const uint8x16_t z = veorq_u8(h, h); - y = veorq_u8(r0, y); - y = vrbitq_u8(y); - const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); - t0 = vextq_u8(y, y, 8); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y)); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y)); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0)); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0)); - t0 = veorq_u8(t0, t1); - t1 = vextq_u8(z, t0, 8); - r0 = veorq_u8(r0, t1); - t1 = vextq_u8(t0, z, 8); - r1 = veorq_u8(r1, t1); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p)); - t1 = vextq_u8(t0, z, 8); - r1 = veorq_u8(r1, t1); - t1 = vextq_u8(z, t0, 8); - r0 = veorq_u8(r0, t1); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p)); - return vrbitq_u8(veorq_u8(r0, t0)); + uint8x16_t r0, r1, t0, t1; + r0 = vld1q_u8(b); + const uint8x16_t z = veorq_u8(h, h); + y = veorq_u8(r0, y); + y = vrbitq_u8(y); + const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); + t0 = vextq_u8(y, y, 8); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y)); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y)); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0)); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0)); + t0 = veorq_u8(t0, t1); + t1 = vextq_u8(z, t0, 8); + r0 = veorq_u8(r0, t1); + t1 = vextq_u8(t0, z, 8); + r1 = veorq_u8(r1, t1); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p)); + t1 = vextq_u8(t0, z, 8); + r1 = veorq_u8(r1, t1); + t1 = vextq_u8(z, t0, 8); + r0 = veorq_u8(r0, t1); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p)); + return vrbitq_u8(veorq_u8(r0, t0)); } -} // anonymous namespace +} // anonymous namespace -void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept +void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept { - uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); - const uint8x16_t h = _aes.p_k.neon.h; + uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); + const uint8x16_t h = _aes.p_k.neon.h; - if (_rp) { - for(;;) { - if (!len) - return; - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y = s_clmul_armneon_crypto(h, y, _r); - break; - } - } - } + if (_rp) { + for (;;) { + if (! len) + return; + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y = s_clmul_armneon_crypto(h, y, _r); + break; + } + } + } - while (len >= 16) { - y = s_clmul_armneon_crypto(h, y, in); - in += 16; - len -= 16; - } + while (len >= 16) { + y = s_clmul_armneon_crypto(h, y, in); + in += 16; + len -= 16; + } - vst1q_u8(reinterpret_cast(_y), y); + vst1q_u8(reinterpret_cast(_y), y); - for (unsigned int i = 0; i < len; ++i) - _r[i] = in[i]; - _rp = len; // len is always less than 16 here + for (unsigned int i = 0; i < len; ++i) + _r[i] = in[i]; + _rp = len; // len is always less than 16 here } void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept { - uint64_t tmp[2]; - uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); - const uint8x16_t h = _aes.p_k.neon.h; + uint64_t tmp[2]; + uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); + const uint8x16_t h = _aes.p_k.neon.h; - if (_rp) { - while (_rp < 16) - _r[_rp++] = 0; - y = s_clmul_armneon_crypto(h, y, _r); - } + if (_rp) { + while (_rp < 16) + _r[_rp++] = 0; + y = s_clmul_armneon_crypto(h, y, _r); + } - tmp[0] = Utils::hton((uint64_t)_len << 3U); - tmp[1] = 0; - y = s_clmul_armneon_crypto(h, y, reinterpret_cast(tmp)); + tmp[0] = Utils::hton((uint64_t)_len << 3U); + tmp[1] = 0; + y = s_clmul_armneon_crypto(h, y, reinterpret_cast(tmp)); - Utils::copy< 12 >(tmp, _iv); + Utils::copy<12>(tmp, _iv); #if __BYTE_ORDER == __BIG_ENDIAN - reinterpret_cast(tmp)[3] = 0x00000001; + reinterpret_cast(tmp)[3] = 0x00000001; #else - reinterpret_cast(tmp)[3] = 0x01000000; + reinterpret_cast(tmp)[3] = 0x01000000; #endif - _aes.encrypt(tmp, tmp); + _aes.encrypt(tmp, tmp); - uint8x16_t yy = y; - Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast(&yy)[0]); - Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast(&yy)[1]); + uint8x16_t yy = y; + Utils::storeMachineEndian(tag, tmp[0] ^ reinterpret_cast(&yy)[0]); + Utils::storeMachineEndian(tag + 8, tmp[1] ^ reinterpret_cast(&yy)[1]); } -void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept +void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept { - uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast(_ctr))); - const uint32x4_t one = {0,0,0,1}; + uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast(_ctr))); + const uint32x4_t one = { 0, 0, 0, 1 }; - uint8x16_t k0 = _aes.p_k.neon.ek[0]; - uint8x16_t k1 = _aes.p_k.neon.ek[1]; - uint8x16_t k2 = _aes.p_k.neon.ek[2]; - uint8x16_t k3 = _aes.p_k.neon.ek[3]; - uint8x16_t k4 = _aes.p_k.neon.ek[4]; - uint8x16_t k5 = _aes.p_k.neon.ek[5]; - uint8x16_t k6 = _aes.p_k.neon.ek[6]; - uint8x16_t k7 = _aes.p_k.neon.ek[7]; - uint8x16_t k8 = _aes.p_k.neon.ek[8]; - uint8x16_t k9 = _aes.p_k.neon.ek[9]; - uint8x16_t k10 = _aes.p_k.neon.ek[10]; - uint8x16_t k11 = _aes.p_k.neon.ek[11]; - uint8x16_t k12 = _aes.p_k.neon.ek[12]; - uint8x16_t k13 = _aes.p_k.neon.ek[13]; - uint8x16_t k14 = _aes.p_k.neon.ek[14]; + uint8x16_t k0 = _aes.p_k.neon.ek[0]; + uint8x16_t k1 = _aes.p_k.neon.ek[1]; + uint8x16_t k2 = _aes.p_k.neon.ek[2]; + uint8x16_t k3 = _aes.p_k.neon.ek[3]; + uint8x16_t k4 = _aes.p_k.neon.ek[4]; + uint8x16_t k5 = _aes.p_k.neon.ek[5]; + uint8x16_t k6 = _aes.p_k.neon.ek[6]; + uint8x16_t k7 = _aes.p_k.neon.ek[7]; + uint8x16_t k8 = _aes.p_k.neon.ek[8]; + uint8x16_t k9 = _aes.p_k.neon.ek[9]; + uint8x16_t k10 = _aes.p_k.neon.ek[10]; + uint8x16_t k11 = _aes.p_k.neon.ek[11]; + uint8x16_t k12 = _aes.p_k.neon.ek[12]; + uint8x16_t k13 = _aes.p_k.neon.ek[13]; + uint8x16_t k14 = _aes.p_k.neon.ek[14]; - unsigned int totalLen = _len; - if ((totalLen & 15U) != 0) { - for (;;) { - if (unlikely(!len)) { - vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); - _len = totalLen; - return; - } - --len; - out[totalLen++] = *(in++); - if ((totalLen & 15U) == 0) { - uint8_t *const otmp = out + (totalLen - 16); - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t pt = vld1q_u8(otmp); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - vst1q_u8(otmp, veorq_u8(pt, d0)); - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - break; - } - } - } + unsigned int totalLen = _len; + if ((totalLen & 15U) != 0) { + for (;;) { + if (unlikely(! len)) { + vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); + _len = totalLen; + return; + } + --len; + out[totalLen++] = *(in++); + if ((totalLen & 15U) == 0) { + uint8_t* const otmp = out + (totalLen - 16); + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t pt = vld1q_u8(otmp); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + vst1q_u8(otmp, veorq_u8(pt, d0)); + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + break; + } + } + } - out += totalLen; - _len = totalLen + len; + out += totalLen; + _len = totalLen + len; - if (likely(len >= 64)) { - const uint32x4_t four = vshlq_n_u32(one, 2); - uint8x16_t dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - uint8x16_t dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, one); - uint8x16_t dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, one); - for (;;) { - len -= 64; - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t d1 = vrev32q_u8(dd1); - uint8x16_t d2 = vrev32q_u8(dd2); - uint8x16_t d3 = vrev32q_u8(dd3); - uint8x16_t pt0 = vld1q_u8(in); - uint8x16_t pt1 = vld1q_u8(in + 16); - uint8x16_t pt2 = vld1q_u8(in + 32); - uint8x16_t pt3 = vld1q_u8(in + 48); + if (likely(len >= 64)) { + const uint32x4_t four = vshlq_n_u32(one, 2); + uint8x16_t dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + uint8x16_t dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, one); + uint8x16_t dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, one); + for (;;) { + len -= 64; + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t d1 = vrev32q_u8(dd1); + uint8x16_t d2 = vrev32q_u8(dd2); + uint8x16_t d3 = vrev32q_u8(dd3); + uint8x16_t pt0 = vld1q_u8(in); + uint8x16_t pt1 = vld1q_u8(in + 16); + uint8x16_t pt2 = vld1q_u8(in + 32); + uint8x16_t pt3 = vld1q_u8(in + 48); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k0)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k0)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k1)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k1)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k2)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k2)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k3)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k3)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k4)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k4)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k5)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k5)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k6)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k6)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k7)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k7)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k8)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k8)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k9)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k9)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k10)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k10)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k11)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k11)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k12)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k12)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - d1 = veorq_u8(vaeseq_u8(d1, k13), k14); - d2 = veorq_u8(vaeseq_u8(d2, k13), k14); - d3 = veorq_u8(vaeseq_u8(d3, k13), k14); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k0)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k0)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k1)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k1)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k2)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k2)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k3)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k3)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k4)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k4)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k5)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k5)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k6)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k6)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k7)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k7)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k8)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k8)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k9)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k9)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k10)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k10)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k11)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k11)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k12)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k12)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + d1 = veorq_u8(vaeseq_u8(d1, k13), k14); + d2 = veorq_u8(vaeseq_u8(d2, k13), k14); + d3 = veorq_u8(vaeseq_u8(d3, k13), k14); - d0 = veorq_u8(pt0, d0); - d1 = veorq_u8(pt1, d1); - d2 = veorq_u8(pt2, d2); - d3 = veorq_u8(pt3, d3); + d0 = veorq_u8(pt0, d0); + d1 = veorq_u8(pt1, d1); + d2 = veorq_u8(pt2, d2); + d3 = veorq_u8(pt3, d3); - vst1q_u8(out, d0); - vst1q_u8(out + 16, d1); - vst1q_u8(out + 32, d2); - vst1q_u8(out + 48, d3); + vst1q_u8(out, d0); + vst1q_u8(out + 16, d1); + vst1q_u8(out + 32, d2); + vst1q_u8(out + 48, d3); - out += 64; - in += 64; + out += 64; + in += 64; - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, four); - if (unlikely(len < 64)) - break; - dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, four); - dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, four); - dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd3, four); - } - } + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, four); + if (unlikely(len < 64)) + break; + dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, four); + dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, four); + dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd3, four); + } + } - while (len >= 16) { - len -= 16; - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t pt = vld1q_u8(in); - in += 16; - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - vst1q_u8(out, veorq_u8(pt, d0)); - out += 16; - } + while (len >= 16) { + len -= 16; + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t pt = vld1q_u8(in); + in += 16; + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + vst1q_u8(out, veorq_u8(pt, d0)); + out += 16; + } - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - for (unsigned int i = 0; i < len; ++i) - out[i] = in[i]; + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + for (unsigned int i = 0; i < len; ++i) + out[i] = in[i]; - vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); + vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); } -#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U)) +#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) \ + ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) \ + + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U)) #define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U)) -#define ZT_INIT_ARMNEON_CRYPTO_NK 8 -#define ZT_INIT_ARMNEON_CRYPTO_NB 4 -#define ZT_INIT_ARMNEON_CRYPTO_NR 14 +#define ZT_INIT_ARMNEON_CRYPTO_NK 8 +#define ZT_INIT_ARMNEON_CRYPTO_NB 4 +#define ZT_INIT_ARMNEON_CRYPTO_NR 14 -void AES::p_init_armneon_crypto(const uint8_t *key) noexcept +void AES::p_init_armneon_crypto(const uint8_t* key) noexcept { - static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, - 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, - 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + static const uint8_t s_sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, + 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, + 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, + 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, + 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, + 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, + 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16 + }; - uint64_t h[2]; - uint32_t *const w = reinterpret_cast(p_k.neon.ek); + uint64_t h[2]; + uint32_t* const w = reinterpret_cast(p_k.neon.ek); - for (unsigned int i=0;i(&(p_k.neon.h), h); - p_k.neon.h = vrbitq_u8(p_k.neon.h); - p_k.sw.h[0] = Utils::ntoh(h[0]); - p_k.sw.h[1] = Utils::ntoh(h[1]); + p_encrypt_armneon_crypto(Utils::ZERO256, h); + Utils::copy<16>(&(p_k.neon.h), h); + p_k.neon.h = vrbitq_u8(p_k.neon.h); + p_k.sw.h[0] = Utils::ntoh(h[0]); + p_k.sw.h[1] = Utils::ntoh(h[1]); } -void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept +void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept { - uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[3])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[4])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[5])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[6])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[7])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[8])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[9])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[10])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); - tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); - vst1q_u8(reinterpret_cast(out), tmp); + uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[3])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[4])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[5])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[6])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[7])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[8])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[9])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[10])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); + tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); + vst1q_u8(reinterpret_cast(out), tmp); } -void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept +void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept { - uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[3])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[4])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[5])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[6])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[7])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[8])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[9])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[10])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); - tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); - vst1q_u8(reinterpret_cast(out), tmp); + uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[3])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[4])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[5])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[6])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[7])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[8])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[9])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[10])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); + tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); + vst1q_u8(reinterpret_cast(out), tmp); } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_AES_NEON +#endif // ZT_AES_NEON diff --git a/core/Address.hpp b/core/Address.hpp index f96f72def..eaef43dd2 100644 --- a/core/Address.hpp +++ b/core/Address.hpp @@ -15,9 +15,9 @@ #define ZT_ADDRESS_HPP #include "Constants.hpp" -#include "Utils.hpp" -#include "TriviallyCopyable.hpp" #include "Containers.hpp" +#include "TriviallyCopyable.hpp" +#include "Utils.hpp" #define ZT_ADDRESS_STRING_SIZE_MAX (ZT_ADDRESS_LENGTH_HEX + 1) @@ -28,136 +28,192 @@ namespace ZeroTier { * * This is merely a 40-bit short address packed into a uint64_t and wrapped with methods. */ -class Address : public TriviallyCopyable -{ -public: - ZT_INLINE Address() noexcept: _a(0) - {} +class Address : public TriviallyCopyable { + public: + ZT_INLINE Address() noexcept : _a(0) + { + } - ZT_INLINE Address(const uint64_t a) noexcept: _a(a) - {} + ZT_INLINE Address(const uint64_t a) noexcept : _a(a) + { + } - explicit ZT_INLINE Address(const uint8_t b[5]) noexcept: - _a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]) - {} + explicit ZT_INLINE Address(const uint8_t b[5]) noexcept + : _a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) + | (uint64_t)b[4]) + { + } - ZT_INLINE Address &operator=(const uint64_t a) noexcept - { _a = a; return *this; } + ZT_INLINE Address& operator=(const uint64_t a) noexcept + { + _a = a; + return *this; + } - /** - * @param bits Raw address -- 5 bytes, big-endian byte order - * @param len Length of array - */ - ZT_INLINE void setTo(const uint8_t b[5]) noexcept - { _a = ((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]; } + /** + * @param bits Raw address -- 5 bytes, big-endian byte order + * @param len Length of array + */ + ZT_INLINE void setTo(const uint8_t b[5]) noexcept + { + _a = ((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) + | (uint64_t)b[4]; + } - /** - * @param bits Buffer to hold 5-byte address in big-endian byte order - * @param len Length of array - */ - ZT_INLINE void copyTo(uint8_t b[5]) const noexcept - { - const uint64_t a = _a; - b[0] = (uint8_t)(a >> 32U); - b[1] = (uint8_t)(a >> 24U); - b[2] = (uint8_t)(a >> 16U); - b[3] = (uint8_t)(a >> 8U); - b[4] = (uint8_t)a; - } + /** + * @param bits Buffer to hold 5-byte address in big-endian byte order + * @param len Length of array + */ + ZT_INLINE void copyTo(uint8_t b[5]) const noexcept + { + const uint64_t a = _a; + b[0] = (uint8_t)(a >> 32U); + b[1] = (uint8_t)(a >> 24U); + b[2] = (uint8_t)(a >> 16U); + b[3] = (uint8_t)(a >> 8U); + b[4] = (uint8_t)a; + } - /** - * @return Integer containing address (0 to 2^40) - */ - ZT_INLINE uint64_t toInt() const noexcept - { return _a; } + /** + * @return Integer containing address (0 to 2^40) + */ + ZT_INLINE uint64_t toInt() const noexcept + { + return _a; + } - /** - * Set address to zero/NIL - */ - ZT_INLINE void zero() noexcept - { _a = 0; } + /** + * Set address to zero/NIL + */ + ZT_INLINE void zero() noexcept + { + _a = 0; + } - /** - * @param s String with at least 11 characters of space available (10 + terminating NULL) - * @return Hexadecimal string - */ - ZT_INLINE char *toString(char s[ZT_ADDRESS_STRING_SIZE_MAX]) const noexcept - { - const uint64_t a = _a; - const unsigned int m = 0xf; - s[0] = Utils::HEXCHARS[(unsigned int)(a >> 36U) & m]; - s[1] = Utils::HEXCHARS[(unsigned int)(a >> 32U) & m]; - s[2] = Utils::HEXCHARS[(unsigned int)(a >> 28U) & m]; - s[3] = Utils::HEXCHARS[(unsigned int)(a >> 24U) & m]; - s[4] = Utils::HEXCHARS[(unsigned int)(a >> 20U) & m]; - s[5] = Utils::HEXCHARS[(unsigned int)(a >> 16U) & m]; - s[6] = Utils::HEXCHARS[(unsigned int)(a >> 12U) & m]; - s[7] = Utils::HEXCHARS[(unsigned int)(a >> 8U) & m]; - s[8] = Utils::HEXCHARS[(unsigned int)(a >> 4U) & m]; - s[9] = Utils::HEXCHARS[(unsigned int)a & m]; - s[10] = 0; - return s; - } + /** + * @param s String with at least 11 characters of space available (10 + terminating NULL) + * @return Hexadecimal string + */ + ZT_INLINE char* toString(char s[ZT_ADDRESS_STRING_SIZE_MAX]) const noexcept + { + const uint64_t a = _a; + const unsigned int m = 0xf; + s[0] = Utils::HEXCHARS[(unsigned int)(a >> 36U) & m]; + s[1] = Utils::HEXCHARS[(unsigned int)(a >> 32U) & m]; + s[2] = Utils::HEXCHARS[(unsigned int)(a >> 28U) & m]; + s[3] = Utils::HEXCHARS[(unsigned int)(a >> 24U) & m]; + s[4] = Utils::HEXCHARS[(unsigned int)(a >> 20U) & m]; + s[5] = Utils::HEXCHARS[(unsigned int)(a >> 16U) & m]; + s[6] = Utils::HEXCHARS[(unsigned int)(a >> 12U) & m]; + s[7] = Utils::HEXCHARS[(unsigned int)(a >> 8U) & m]; + s[8] = Utils::HEXCHARS[(unsigned int)(a >> 4U) & m]; + s[9] = Utils::HEXCHARS[(unsigned int)a & m]; + s[10] = 0; + return s; + } - ZT_INLINE String toString() const - { - char s[ZT_ADDRESS_STRING_SIZE_MAX]; - toString(s); - return String(s); - } + ZT_INLINE String toString() const + { + char s[ZT_ADDRESS_STRING_SIZE_MAX]; + toString(s); + return String(s); + } - /** - * Check if this address is reserved - * - * The all-zero null address and any address beginning with 0xff are - * reserved. (0xff is reserved for future use to designate possibly - * longer addresses, addresses based on IPv6 innards, etc.) - * - * @return True if address is reserved and may not be used - */ - ZT_INLINE bool isReserved() const noexcept - { return ((!_a) || ((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); } + /** + * Check if this address is reserved + * + * The all-zero null address and any address beginning with 0xff are + * reserved. (0xff is reserved for future use to designate possibly + * longer addresses, addresses based on IPv6 innards, etc.) + * + * @return True if address is reserved and may not be used + */ + ZT_INLINE bool isReserved() const noexcept + { + return ((! _a) || ((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)_a; } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)_a; + } - ZT_INLINE operator bool() const noexcept - { return (_a != 0); } + ZT_INLINE operator bool() const noexcept + { + return (_a != 0); + } - ZT_INLINE operator uint64_t() const noexcept - { return _a; } + ZT_INLINE operator uint64_t() const noexcept + { + return _a; + } - ZT_INLINE bool operator==(const Address &a) const noexcept - { return _a == a._a; } - ZT_INLINE bool operator!=(const Address &a) const noexcept - { return _a != a._a; } - ZT_INLINE bool operator>(const Address &a) const noexcept - { return _a > a._a; } - ZT_INLINE bool operator<(const Address &a) const noexcept - { return _a < a._a; } - ZT_INLINE bool operator>=(const Address &a) const noexcept - { return _a >= a._a; } - ZT_INLINE bool operator<=(const Address &a) const noexcept - { return _a <= a._a; } - ZT_INLINE bool operator==(const uint64_t a) const noexcept - { return _a == a; } - ZT_INLINE bool operator!=(const uint64_t a) const noexcept - { return _a != a; } - ZT_INLINE bool operator>(const uint64_t a) const noexcept - { return _a > a; } - ZT_INLINE bool operator<(const uint64_t a) const noexcept - { return _a < a; } - ZT_INLINE bool operator>=(const uint64_t a) const noexcept - { return _a >= a; } - ZT_INLINE bool operator<=(const uint64_t a) const noexcept - { return _a <= a; } + ZT_INLINE bool operator==(const Address& a) const noexcept + { + return _a == a._a; + } -private: - uint64_t _a; + ZT_INLINE bool operator!=(const Address& a) const noexcept + { + return _a != a._a; + } + + ZT_INLINE bool operator>(const Address& a) const noexcept + { + return _a > a._a; + } + + ZT_INLINE bool operator<(const Address& a) const noexcept + { + return _a < a._a; + } + + ZT_INLINE bool operator>=(const Address& a) const noexcept + { + return _a >= a._a; + } + + ZT_INLINE bool operator<=(const Address& a) const noexcept + { + return _a <= a._a; + } + + ZT_INLINE bool operator==(const uint64_t a) const noexcept + { + return _a == a; + } + + ZT_INLINE bool operator!=(const uint64_t a) const noexcept + { + return _a != a; + } + + ZT_INLINE bool operator>(const uint64_t a) const noexcept + { + return _a > a; + } + + ZT_INLINE bool operator<(const uint64_t a) const noexcept + { + return _a < a; + } + + ZT_INLINE bool operator>=(const uint64_t a) const noexcept + { + return _a >= a; + } + + ZT_INLINE bool operator<=(const uint64_t a) const noexcept + { + return _a <= a; + } + + private: + uint64_t _a; }; -static_assert(sizeof(Address) == sizeof(uint64_t),"Address has unnecessary extra padding"); +static_assert(sizeof(Address) == sizeof(uint64_t), "Address has unnecessary extra padding"); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Buf.cpp b/core/Buf.cpp index c0229fcd0..38118fb75 100644 --- a/core/Buf.cpp +++ b/core/Buf.cpp @@ -12,89 +12,94 @@ /****/ #include "Buf.hpp" + #include "Spinlock.hpp" namespace ZeroTier { -static std::atomic< uintptr_t > s_pool(0); -static std::atomic< long > s_allocated(0); +static std::atomic s_pool(0); +static std::atomic s_allocated(0); // uintptr_max can never be a valid pointer, so use it to indicate that s_pool is locked (very short duration spinlock) #define ZT_ATOMIC_PTR_LOCKED (~((uintptr_t)0)) -void *Buf::operator new(std::size_t sz) +void* Buf::operator new(std::size_t sz) { - uintptr_t bb; - for (;;) { - bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); + uintptr_t bb; + for (;;) { + bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); - if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { - Buf *b; - if (likely(bb != 0)) { - b = reinterpret_cast(bb); - s_pool.store(b->__nextInPool, std::memory_order_release); - } else { - s_pool.store(0, std::memory_order_release); - b = reinterpret_cast(malloc(sz)); - if (!b) - throw Utils::BadAllocException; - s_allocated.fetch_add(1, std::memory_order_relaxed); - } + if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { + Buf* b; + if (likely(bb != 0)) { + b = reinterpret_cast(bb); + s_pool.store(b->__nextInPool, std::memory_order_release); + } + else { + s_pool.store(0, std::memory_order_release); + b = reinterpret_cast(malloc(sz)); + if (! b) + throw Utils::BadAllocException; + s_allocated.fetch_add(1, std::memory_order_relaxed); + } - b->__refCount.store(0, std::memory_order_relaxed); + b->__refCount.store(0, std::memory_order_relaxed); - return reinterpret_cast(b); - } + return reinterpret_cast(b); + } - Spinlock::pause(); - } + Spinlock::pause(); + } } -void Buf::operator delete(void *ptr) +void Buf::operator delete(void* ptr) { - if (likely(ptr != nullptr)) { - if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) { - s_allocated.fetch_sub(1, std::memory_order_relaxed); - free(ptr); - } else { - uintptr_t bb; - for (;;) { - bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); - if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { - reinterpret_cast(ptr)->__nextInPool = bb; - s_pool.store(reinterpret_cast(ptr), std::memory_order_release); - return; - } - Spinlock::pause(); - } - } - } + if (likely(ptr != nullptr)) { + if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) { + s_allocated.fetch_sub(1, std::memory_order_relaxed); + free(ptr); + } + else { + uintptr_t bb; + for (;;) { + bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); + if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { + reinterpret_cast(ptr)->__nextInPool = bb; + s_pool.store(reinterpret_cast(ptr), std::memory_order_release); + return; + } + Spinlock::pause(); + } + } + } } void Buf::freePool() noexcept { - uintptr_t bb; - for (;;) { - bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); + uintptr_t bb; + for (;;) { + bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); - if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { - s_pool.store(0, std::memory_order_release); + if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { + s_pool.store(0, std::memory_order_release); - while (bb != 0) { - const uintptr_t next = reinterpret_cast(bb)->__nextInPool; - s_allocated.fetch_sub(1, std::memory_order_relaxed); - free(reinterpret_cast(bb)); - bb = next; - } + while (bb != 0) { + const uintptr_t next = reinterpret_cast(bb)->__nextInPool; + s_allocated.fetch_sub(1, std::memory_order_relaxed); + free(reinterpret_cast(bb)); + bb = next; + } - return; - } + return; + } - Spinlock::pause(); - } + Spinlock::pause(); + } } long Buf::poolAllocated() noexcept -{ return s_allocated.load(std::memory_order_relaxed); } +{ + return s_allocated.load(std::memory_order_relaxed); +} -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Buf.hpp b/core/Buf.hpp index 4326d87f2..63778ac03 100644 --- a/core/Buf.hpp +++ b/core/Buf.hpp @@ -15,16 +15,16 @@ #define ZT_BUF_HPP #include "Constants.hpp" -#include "Utils.hpp" -#include "SharedPtr.hpp" -#include "Mutex.hpp" -#include "TriviallyCopyable.hpp" #include "FCV.hpp" +#include "Mutex.hpp" +#include "SharedPtr.hpp" +#include "TriviallyCopyable.hpp" +#include "Utils.hpp" -#include -#include #include #include +#include +#include // Buffers are 16384 bytes in size because this is the smallest size that can hold any packet // and is a power of two. It needs to be a power of two because masking is significantly faster @@ -77,790 +77,782 @@ namespace ZeroTier { * * @tparam U Type to overlap with data bytes in data union (can't be larger than ZT_BUF_MEM_SIZE) */ -class Buf -{ - friend class SharedPtr< Buf >; +class Buf { + friend class SharedPtr; -public: - // New and delete operators that allocate Buf instances from a shared lock-free memory pool. - static void *operator new(std::size_t sz); + public: + // New and delete operators that allocate Buf instances from a shared lock-free memory pool. + static void* operator new(std::size_t sz); - static void operator delete(void *ptr); + static void operator delete(void* ptr); - /** - * Raw data held in buffer - * - * The additional eight bytes should not be used and should be considered undefined. - * They exist to allow reads and writes of integer types to silently overflow if a - * read or write is performed at the end of the buffer. - */ - uint8_t unsafeData[ZT_BUF_MEM_SIZE + 8]; + /** + * Raw data held in buffer + * + * The additional eight bytes should not be used and should be considered undefined. + * They exist to allow reads and writes of integer types to silently overflow if a + * read or write is performed at the end of the buffer. + */ + uint8_t unsafeData[ZT_BUF_MEM_SIZE + 8]; - /** - * Free all instances of Buf in shared pool. - * - * New buffers will be created and the pool repopulated if get() is called - * and outstanding buffers will still be returned to the pool. This just - * frees buffers currently held in reserve. - */ - static void freePool() noexcept; + /** + * Free all instances of Buf in shared pool. + * + * New buffers will be created and the pool repopulated if get() is called + * and outstanding buffers will still be returned to the pool. This just + * frees buffers currently held in reserve. + */ + static void freePool() noexcept; - /** - * @return Number of Buf objects currently allocated via pool mechanism - */ - static long poolAllocated() noexcept; + /** + * @return Number of Buf objects currently allocated via pool mechanism + */ + static long poolAllocated() noexcept; - /** - * Slice is almost exactly like the built-in slice data structure in Go - */ - struct Slice : TriviallyCopyable - { - ZT_INLINE Slice(const SharedPtr< Buf > &b_, const unsigned int s_, const unsigned int e_) noexcept: b(b_), s(s_), e(e_) - {} + /** + * Slice is almost exactly like the built-in slice data structure in Go + */ + struct Slice : TriviallyCopyable { + ZT_INLINE Slice(const SharedPtr& b_, const unsigned int s_, const unsigned int e_) noexcept + : b(b_) + , s(s_) + , e(e_) + { + } - ZT_INLINE Slice() noexcept: b(), s(0), e(0) - {} + ZT_INLINE Slice() noexcept + : b() + , s(0) + , e(0) + { + } - ZT_INLINE operator bool() const noexcept - { return (b); } + ZT_INLINE operator bool() const noexcept + { + return (b); + } - ZT_INLINE unsigned int size() const noexcept - { return (e - s); } + ZT_INLINE unsigned int size() const noexcept + { + return (e - s); + } - ZT_INLINE void zero() noexcept - { - b.zero(); - s = 0; - e = 0; - } + ZT_INLINE void zero() noexcept + { + b.zero(); + s = 0; + e = 0; + } - /** - * Buffer holding slice data - */ - SharedPtr< Buf > b; + /** + * Buffer holding slice data + */ + SharedPtr b; - /** - * Index of start of data in slice - */ - unsigned int s; + /** + * Index of start of data in slice + */ + unsigned int s; - /** - * Index of end of data in slice (make sure it's greater than or equal to 's'!) - */ - unsigned int e; - }; + /** + * Index of end of data in slice (make sure it's greater than or equal to 's'!) + */ + unsigned int e; + }; - /** - * A vector of slices making up a packet that might span more than one buffer. - */ - class PacketVector : public ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS > - { - public: - ZT_INLINE PacketVector() : ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS >() - {} + /** + * A vector of slices making up a packet that might span more than one buffer. + */ + class PacketVector : public ZeroTier::FCV { + public: + ZT_INLINE PacketVector() : ZeroTier::FCV() + { + } - ZT_INLINE unsigned int totalSize() const noexcept - { - unsigned int size = 0; - for (PacketVector::const_iterator s(begin()); s != end(); ++s) - size += s->e - s->s; - return size; - } + ZT_INLINE unsigned int totalSize() const noexcept + { + unsigned int size = 0; + for (PacketVector::const_iterator s(begin()); s != end(); ++s) + size += s->e - s->s; + return size; + } - /** - * Merge this packet vector into a single destination buffer - * - * @param b Destination buffer - * @return Size of data in destination or -1 on error - */ - ZT_INLINE int mergeCopy(Buf &b) const noexcept - { - unsigned int size = 0; - for (PacketVector::const_iterator s(begin()); s != end(); ++s) { - const unsigned int start = s->s; - const unsigned int rem = s->e - start; - if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) { - Utils::copy(b.unsafeData + size, s->b->unsafeData + start, rem); - size += rem; - } else { - return -1; - } - } - return (int)size; - } + /** + * Merge this packet vector into a single destination buffer + * + * @param b Destination buffer + * @return Size of data in destination or -1 on error + */ + ZT_INLINE int mergeCopy(Buf& b) const noexcept + { + unsigned int size = 0; + for (PacketVector::const_iterator s(begin()); s != end(); ++s) { + const unsigned int start = s->s; + const unsigned int rem = s->e - start; + if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) { + Utils::copy(b.unsafeData + size, s->b->unsafeData + start, rem); + size += rem; + } + else { + return -1; + } + } + return (int)size; + } - /** - * Merge this packet vector into a single destination buffer with an arbitrary copy function - * - * This can be used to e.g. simultaneously merge and decrypt a packet. - * - * @param b Destination buffer - * @param simpleCopyBefore Don't start using copyFunction until this index (0 to always use) - * @param copyFunction Function to invoke with memcpy-like arguments: (dest, source, size) - * @tparam F Type of copyFunction (typically inferred) - * @return Size of data in destination or -1 on error - */ - template< typename F > - ZT_INLINE int mergeMap(Buf &b, const unsigned int simpleCopyBefore, F copyFunction) const noexcept - { - unsigned int size = 0; - for (PacketVector::const_iterator s(begin()); s != end(); ++s) { - unsigned int start = s->s; - unsigned int rem = s->e - start; - if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) { - if (size < simpleCopyBefore) { - unsigned int sc = simpleCopyBefore - size; - if (unlikely(sc > rem)) - sc = rem; - Utils::copy(b.unsafeData + size, s->b->unsafeData + start, sc); - start += sc; - rem -= sc; - } + /** + * Merge this packet vector into a single destination buffer with an arbitrary copy function + * + * This can be used to e.g. simultaneously merge and decrypt a packet. + * + * @param b Destination buffer + * @param simpleCopyBefore Don't start using copyFunction until this index (0 to always use) + * @param copyFunction Function to invoke with memcpy-like arguments: (dest, source, size) + * @tparam F Type of copyFunction (typically inferred) + * @return Size of data in destination or -1 on error + */ + template + ZT_INLINE int mergeMap(Buf& b, const unsigned int simpleCopyBefore, F copyFunction) const noexcept + { + unsigned int size = 0; + for (PacketVector::const_iterator s(begin()); s != end(); ++s) { + unsigned int start = s->s; + unsigned int rem = s->e - start; + if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) { + if (size < simpleCopyBefore) { + unsigned int sc = simpleCopyBefore - size; + if (unlikely(sc > rem)) + sc = rem; + Utils::copy(b.unsafeData + size, s->b->unsafeData + start, sc); + start += sc; + rem -= sc; + } - if (likely(rem > 0)) { - copyFunction(b.unsafeData + size, s->b->unsafeData + start, rem); - size += rem; - } - } else { - return -1; - } - } - return (int)size; - } - }; + if (likely(rem > 0)) { + copyFunction(b.unsafeData + size, s->b->unsafeData + start, rem); + size += rem; + } + } + else { + return -1; + } + } + return (int)size; + } + }; - /** - * Create a new uninitialized buffer with undefined contents (use clear() to zero if needed) - */ - ZT_INLINE Buf() noexcept: __nextInPool(0), __refCount(0) - {} + /** + * Create a new uninitialized buffer with undefined contents (use clear() to zero if needed) + */ + ZT_INLINE Buf() noexcept + : __nextInPool(0) + , __refCount(0) + { + } - /** - * Create a new buffer and copy data into it - */ - ZT_INLINE Buf(const void *const data, const unsigned int len) noexcept: - __refCount(0) - { - Utils::copy(unsafeData, data, len); - } + /** + * Create a new buffer and copy data into it + */ + ZT_INLINE Buf(const void* const data, const unsigned int len) noexcept : __refCount(0) + { + Utils::copy(unsafeData, data, len); + } - ZT_INLINE Buf(const Buf &b2) noexcept: - __nextInPool(0), - __refCount(0) - { - Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData); - } + ZT_INLINE Buf(const Buf& b2) noexcept + : __nextInPool(0) + , __refCount(0) + { + Utils::copy(unsafeData, b2.unsafeData); + } - ZT_INLINE Buf &operator=(const Buf &b2) noexcept - { - if (this != &b2) - Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData); - return *this; - } + ZT_INLINE Buf& operator=(const Buf& b2) noexcept + { + if (this != &b2) + Utils::copy(unsafeData, b2.unsafeData); + return *this; + } - /** - * Check for overflow beyond the size of the buffer - * - * This is used to check for overflow when writing. It returns true if the iterator - * has passed beyond the capacity of the buffer. - * - * @param ii Iterator to check - * @return True if iterator has read past the size of the buffer - */ - static ZT_INLINE bool writeOverflow(const int &ii) noexcept - { return ((ii - ZT_BUF_MEM_SIZE) > 0); } + /** + * Check for overflow beyond the size of the buffer + * + * This is used to check for overflow when writing. It returns true if the iterator + * has passed beyond the capacity of the buffer. + * + * @param ii Iterator to check + * @return True if iterator has read past the size of the buffer + */ + static ZT_INLINE bool writeOverflow(const int& ii) noexcept + { + return ((ii - ZT_BUF_MEM_SIZE) > 0); + } - /** - * Check for overflow beyond the size of the data that should be in the buffer - * - * This is used to check for overflow when reading, with the second argument being the - * size of the meaningful data actually present in the buffer. - * - * @param ii Iterator to check - * @param size Size of data that should be in buffer - * @return True if iterator has read past the size of the data - */ - static ZT_INLINE bool readOverflow(const int &ii, const unsigned int size) noexcept - { return ((ii - (int)size) > 0); } + /** + * Check for overflow beyond the size of the data that should be in the buffer + * + * This is used to check for overflow when reading, with the second argument being the + * size of the meaningful data actually present in the buffer. + * + * @param ii Iterator to check + * @param size Size of data that should be in buffer + * @return True if iterator has read past the size of the data + */ + static ZT_INLINE bool readOverflow(const int& ii, const unsigned int size) noexcept + { + return ((ii - (int)size) > 0); + } - /** - * Set all memory to zero - */ - ZT_INLINE void clear() noexcept - { - Utils::zero< ZT_BUF_MEM_SIZE >(unsafeData); - } + /** + * Set all memory to zero + */ + ZT_INLINE void clear() noexcept + { + Utils::zero(unsafeData); + } - /** - * Read a byte - * - * @param ii Index value-result parameter (incremented by 1) - * @return Byte (undefined on overflow) - */ - ZT_INLINE uint8_t rI8(int &ii) const noexcept - { - const int s = ii++; - return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK]; - } + /** + * Read a byte + * + * @param ii Index value-result parameter (incremented by 1) + * @return Byte (undefined on overflow) + */ + ZT_INLINE uint8_t rI8(int& ii) const noexcept + { + const int s = ii++; + return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK]; + } - /** - * Read a 16-bit integer - * - * @param ii Index value-result parameter (incremented by 2) - * @return Integer (undefined on overflow) - */ - ZT_INLINE uint16_t rI16(int &ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; - ii += 2; + /** + * Read a 16-bit integer + * + * @param ii Index value-result parameter (incremented by 2) + * @return Integer (undefined on overflow) + */ + ZT_INLINE uint16_t rI16(int& ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + ii += 2; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint16_t)unsafeData[s] << 8U) | - (uint16_t)unsafeData[s + 1]); + return (((uint16_t)unsafeData[s] << 8U) | (uint16_t)unsafeData[s + 1]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Read a 32-bit integer - * - * @param ii Index value-result parameter (incremented by 4) - * @return Integer (undefined on overflow) - */ - ZT_INLINE uint32_t rI32(int &ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; - ii += 4; + /** + * Read a 32-bit integer + * + * @param ii Index value-result parameter (incremented by 4) + * @return Integer (undefined on overflow) + */ + ZT_INLINE uint32_t rI32(int& ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + ii += 4; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint32_t)unsafeData[s] << 24U) | - ((uint32_t)unsafeData[s + 1] << 16U) | - ((uint32_t)unsafeData[s + 2] << 8U) | - (uint32_t)unsafeData[s + 3]); + return ( + ((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s + 1] << 16U) + | ((uint32_t)unsafeData[s + 2] << 8U) | (uint32_t)unsafeData[s + 3]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Read a 64-bit integer - * - * @param ii Index value-result parameter (incremented by 8) - * @return Integer (undefined on overflow) - */ - ZT_INLINE uint64_t rI64(int &ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; - ii += 8; + /** + * Read a 64-bit integer + * + * @param ii Index value-result parameter (incremented by 8) + * @return Integer (undefined on overflow) + */ + ZT_INLINE uint64_t rI64(int& ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + ii += 8; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint64_t)unsafeData[s] << 56U) | - ((uint64_t)unsafeData[s + 1] << 48U) | - ((uint64_t)unsafeData[s + 2] << 40U) | - ((uint64_t)unsafeData[s + 3] << 32U) | - ((uint64_t)unsafeData[s + 4] << 24U) | - ((uint64_t)unsafeData[s + 5] << 16U) | - ((uint64_t)unsafeData[s + 6] << 8U) | - (uint64_t)unsafeData[s + 7]); + return ( + ((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s + 1] << 48U) + | ((uint64_t)unsafeData[s + 2] << 40U) | ((uint64_t)unsafeData[s + 3] << 32U) + | ((uint64_t)unsafeData[s + 4] << 24U) | ((uint64_t)unsafeData[s + 5] << 16U) + | ((uint64_t)unsafeData[s + 6] << 8U) | (uint64_t)unsafeData[s + 7]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Read an object supporting the marshal/unmarshal interface - * - * If the return value is negative the object's state is undefined. A return value of - * zero typically also indicates a problem, though this may depend on the object type. - * - * Since objects may be invalid even if there is no overflow, it's important to check - * the return value of this function in all cases and discard invalid packets as it - * indicates. - * - * @tparam T Object type - * @param ii Index value-result parameter (incremented by object's size in bytes) - * @param obj Object to read - * @return Bytes read or a negative value on unmarshal error (passed from object) or overflow - */ - template< typename T > - ZT_INLINE int rO(int &ii, T &obj) const noexcept - { - if (likely(ii < ZT_BUF_MEM_SIZE)) { - int ms = obj.unmarshal(unsafeData + ii, ZT_BUF_MEM_SIZE - ii); - if (ms > 0) - ii += ms; - return ms; - } - return -1; - } + /** + * Read an object supporting the marshal/unmarshal interface + * + * If the return value is negative the object's state is undefined. A return value of + * zero typically also indicates a problem, though this may depend on the object type. + * + * Since objects may be invalid even if there is no overflow, it's important to check + * the return value of this function in all cases and discard invalid packets as it + * indicates. + * + * @tparam T Object type + * @param ii Index value-result parameter (incremented by object's size in bytes) + * @param obj Object to read + * @return Bytes read or a negative value on unmarshal error (passed from object) or overflow + */ + template ZT_INLINE int rO(int& ii, T& obj) const noexcept + { + if (likely(ii < ZT_BUF_MEM_SIZE)) { + int ms = obj.unmarshal(unsafeData + ii, ZT_BUF_MEM_SIZE - ii); + if (ms > 0) + ii += ms; + return ms; + } + return -1; + } - /** - * Read a C-style string from the buffer, making a copy and advancing the iterator - * - * Use this if the buffer's memory may get changed between reading and processing - * what is read. - * - * @param ii Index value-result parameter (incremented by length of string) - * @param buf Buffer to receive string - * @param bufSize Capacity of buffer in bytes - * @return Pointer to buf or NULL on overflow or error - */ - ZT_INLINE char *rS(int &ii, char *const buf, const unsigned int bufSize) const noexcept - { - const char *const s = (const char *)(unsafeData + ii); - const int sii = ii; - while (ii < ZT_BUF_MEM_SIZE) { - if (unsafeData[ii++] == 0) { - const int l = ii - sii; - if (unlikely((unsigned int)l > bufSize)) - return nullptr; - Utils::copy(buf, s, l); - return buf; - } - } - return nullptr; - } + /** + * Read a C-style string from the buffer, making a copy and advancing the iterator + * + * Use this if the buffer's memory may get changed between reading and processing + * what is read. + * + * @param ii Index value-result parameter (incremented by length of string) + * @param buf Buffer to receive string + * @param bufSize Capacity of buffer in bytes + * @return Pointer to buf or NULL on overflow or error + */ + ZT_INLINE char* rS(int& ii, char* const buf, const unsigned int bufSize) const noexcept + { + const char* const s = (const char*)(unsafeData + ii); + const int sii = ii; + while (ii < ZT_BUF_MEM_SIZE) { + if (unsafeData[ii++] == 0) { + const int l = ii - sii; + if (unlikely((unsigned int)l > bufSize)) + return nullptr; + Utils::copy(buf, s, l); + return buf; + } + } + return nullptr; + } - /** - * Obtain a pointer to a C-style string in the buffer without copying and advance the iterator - * - * The iterator is advanced even if this fails and returns NULL so that readOverflow() - * will indicate that an overflow occurred. As with other reads the string's contents are - * undefined if readOverflow() returns true. - * - * This version avoids a copy and so is faster if the buffer won't be modified between - * reading and processing. - * - * @param ii Index value-result parameter (incremented by length of string) - * @return Pointer to null-terminated C-style string or NULL on overflow or error - */ - ZT_INLINE const char *rSnc(int &ii) const noexcept - { - const char *const s = (const char *)(unsafeData + ii); - while (ii < ZT_BUF_MEM_SIZE) { - if (unsafeData[ii++] == 0) - return s; - } - return nullptr; - } + /** + * Obtain a pointer to a C-style string in the buffer without copying and advance the iterator + * + * The iterator is advanced even if this fails and returns NULL so that readOverflow() + * will indicate that an overflow occurred. As with other reads the string's contents are + * undefined if readOverflow() returns true. + * + * This version avoids a copy and so is faster if the buffer won't be modified between + * reading and processing. + * + * @param ii Index value-result parameter (incremented by length of string) + * @return Pointer to null-terminated C-style string or NULL on overflow or error + */ + ZT_INLINE const char* rSnc(int& ii) const noexcept + { + const char* const s = (const char*)(unsafeData + ii); + while (ii < ZT_BUF_MEM_SIZE) { + if (unsafeData[ii++] == 0) + return s; + } + return nullptr; + } - /** - * Read a byte array from the buffer, making a copy and advancing the iterator - * - * Use this if the buffer's memory may get changed between reading and processing - * what is read. - * - * @param ii Index value-result parameter (incremented by len) - * @param bytes Buffer to contain data to read - * @param len Length of buffer - * @return Pointer to data or NULL on overflow or error - */ - ZT_INLINE uint8_t *rB(int &ii, void *const bytes, const unsigned int len) const noexcept - { - if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) { - Utils::copy(bytes, unsafeData + ii, len); - return reinterpret_cast(bytes); - } - return nullptr; - } + /** + * Read a byte array from the buffer, making a copy and advancing the iterator + * + * Use this if the buffer's memory may get changed between reading and processing + * what is read. + * + * @param ii Index value-result parameter (incremented by len) + * @param bytes Buffer to contain data to read + * @param len Length of buffer + * @return Pointer to data or NULL on overflow or error + */ + ZT_INLINE uint8_t* rB(int& ii, void* const bytes, const unsigned int len) const noexcept + { + if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) { + Utils::copy(bytes, unsafeData + ii, len); + return reinterpret_cast(bytes); + } + return nullptr; + } - /** - * Obtain a pointer to a field in the buffer without copying and advance the iterator - * - * The iterator is advanced even if this fails and returns NULL so that readOverflow() - * will indicate that an overflow occurred. - * - * This version avoids a copy and so is faster if the buffer won't be modified between - * reading and processing. - * - * @param ii Index value-result parameter (incremented by len) - * @param len Length of data field to obtain a pointer to - * @return Pointer to field or NULL on overflow - */ - ZT_INLINE const uint8_t *rBnc(int &ii, unsigned int len) const noexcept - { - const uint8_t *const b = unsafeData + ii; - return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr; - } + /** + * Obtain a pointer to a field in the buffer without copying and advance the iterator + * + * The iterator is advanced even if this fails and returns NULL so that readOverflow() + * will indicate that an overflow occurred. + * + * This version avoids a copy and so is faster if the buffer won't be modified between + * reading and processing. + * + * @param ii Index value-result parameter (incremented by len) + * @param len Length of data field to obtain a pointer to + * @return Pointer to field or NULL on overflow + */ + ZT_INLINE const uint8_t* rBnc(int& ii, unsigned int len) const noexcept + { + const uint8_t* const b = unsafeData + ii; + return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr; + } - /** - * Load a value at an index that is compile time checked against the maximum buffer size - * - * @tparam I Static index - * @return Value - */ - template< unsigned int I > - ZT_INLINE uint8_t lI8() const noexcept - { - static_assert(I < ZT_BUF_MEM_SIZE, "overflow"); - return unsafeData[I]; - } + /** + * Load a value at an index that is compile time checked against the maximum buffer size + * + * @tparam I Static index + * @return Value + */ + template ZT_INLINE uint8_t lI8() const noexcept + { + static_assert(I < ZT_BUF_MEM_SIZE, "overflow"); + return unsafeData[I]; + } - /** - * Load a value at an index that is compile time checked against the maximum buffer size - * - * @tparam I Static index - * @return Value - */ - template< unsigned int I > - ZT_INLINE uint8_t lI16() const noexcept - { - static_assert((I + 1) < ZT_BUF_MEM_SIZE, "overflow"); + /** + * Load a value at an index that is compile time checked against the maximum buffer size + * + * @tparam I Static index + * @return Value + */ + template ZT_INLINE uint8_t lI16() const noexcept + { + static_assert((I + 1) < ZT_BUF_MEM_SIZE, "overflow"); #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint16_t)unsafeData[I] << 8U) | - (uint16_t)unsafeData[I + 1]); + return (((uint16_t)unsafeData[I] << 8U) | (uint16_t)unsafeData[I + 1]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + I)); + return Utils::ntoh(*reinterpret_cast(unsafeData + I)); #endif - } + } - /** - * Load a value at an index that is compile time checked against the maximum buffer size - * - * @tparam I Static index - * @return Value - */ - template< unsigned int I > - ZT_INLINE uint8_t lI32() const noexcept - { - static_assert((I + 3) < ZT_BUF_MEM_SIZE, "overflow"); + /** + * Load a value at an index that is compile time checked against the maximum buffer size + * + * @tparam I Static index + * @return Value + */ + template ZT_INLINE uint8_t lI32() const noexcept + { + static_assert((I + 3) < ZT_BUF_MEM_SIZE, "overflow"); #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint32_t)unsafeData[I] << 24U) | - ((uint32_t)unsafeData[I + 1] << 16U) | - ((uint32_t)unsafeData[I + 2] << 8U) | - (uint32_t)unsafeData[I + 3]); + return ( + ((uint32_t)unsafeData[I] << 24U) | ((uint32_t)unsafeData[I + 1] << 16U) + | ((uint32_t)unsafeData[I + 2] << 8U) | (uint32_t)unsafeData[I + 3]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + I)); + return Utils::ntoh(*reinterpret_cast(unsafeData + I)); #endif - } + } - /** - * Load a value at an index that is compile time checked against the maximum buffer size - * - * @tparam I Static index - * @return Value - */ - template< unsigned int I > - ZT_INLINE uint8_t lI64() const noexcept - { - static_assert((I + 7) < ZT_BUF_MEM_SIZE, "overflow"); + /** + * Load a value at an index that is compile time checked against the maximum buffer size + * + * @tparam I Static index + * @return Value + */ + template ZT_INLINE uint8_t lI64() const noexcept + { + static_assert((I + 7) < ZT_BUF_MEM_SIZE, "overflow"); #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint64_t)unsafeData[I] << 56U) | - ((uint64_t)unsafeData[I + 1] << 48U) | - ((uint64_t)unsafeData[I + 2] << 40U) | - ((uint64_t)unsafeData[I + 3] << 32U) | - ((uint64_t)unsafeData[I + 4] << 24U) | - ((uint64_t)unsafeData[I + 5] << 16U) | - ((uint64_t)unsafeData[I + 6] << 8U) | - (uint64_t)unsafeData[I + 7]); + return ( + ((uint64_t)unsafeData[I] << 56U) | ((uint64_t)unsafeData[I + 1] << 48U) + | ((uint64_t)unsafeData[I + 2] << 40U) | ((uint64_t)unsafeData[I + 3] << 32U) + | ((uint64_t)unsafeData[I + 4] << 24U) | ((uint64_t)unsafeData[I + 5] << 16U) + | ((uint64_t)unsafeData[I + 6] << 8U) | (uint64_t)unsafeData[I + 7]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + I)); + return Utils::ntoh(*reinterpret_cast(unsafeData + I)); #endif - } + } - /** - * Load a value at an index without advancing the index - * - * Note that unlike the rI??() methods this does not increment ii and therefore - * will not necessarily result in a 'true' return from readOverflow(). It does - * however subject 'ii' to soft bounds masking like the gI??() methods. - */ - ZT_INLINE uint8_t lI8(const int ii) const noexcept - { - return unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK]; - } + /** + * Load a value at an index without advancing the index + * + * Note that unlike the rI??() methods this does not increment ii and therefore + * will not necessarily result in a 'true' return from readOverflow(). It does + * however subject 'ii' to soft bounds masking like the gI??() methods. + */ + ZT_INLINE uint8_t lI8(const int ii) const noexcept + { + return unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK]; + } - /** - * Load a value at an index without advancing the index - * - * Note that unlike the rI??() methods this does not increment ii and therefore - * will not necessarily result in a 'true' return from readOverflow(). It does - * however subject 'ii' to soft bounds masking like the gI??() methods. - */ - ZT_INLINE uint16_t lI16(const int ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + /** + * Load a value at an index without advancing the index + * + * Note that unlike the rI??() methods this does not increment ii and therefore + * will not necessarily result in a 'true' return from readOverflow(). It does + * however subject 'ii' to soft bounds masking like the gI??() methods. + */ + ZT_INLINE uint16_t lI16(const int ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint16_t)unsafeData[s] << 8U) | - (uint16_t)unsafeData[s + 1]); + return (((uint16_t)unsafeData[s] << 8U) | (uint16_t)unsafeData[s + 1]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Load a value at an index without advancing the index - * - * Note that unlike the rI??() methods this does not increment ii and therefore - * will not necessarily result in a 'true' return from readOverflow(). It does - * however subject 'ii' to soft bounds masking like the gI??() methods. - */ - ZT_INLINE uint32_t lI32(const int ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + /** + * Load a value at an index without advancing the index + * + * Note that unlike the rI??() methods this does not increment ii and therefore + * will not necessarily result in a 'true' return from readOverflow(). It does + * however subject 'ii' to soft bounds masking like the gI??() methods. + */ + ZT_INLINE uint32_t lI32(const int ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint32_t)unsafeData[s] << 24U) | - ((uint32_t)unsafeData[s + 1] << 16U) | - ((uint32_t)unsafeData[s + 2] << 8U) | - (uint32_t)unsafeData[s + 3]); + return ( + ((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s + 1] << 16U) + | ((uint32_t)unsafeData[s + 2] << 8U) | (uint32_t)unsafeData[s + 3]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Load a value at an index without advancing the index - * - * Note that unlike the rI??() methods this does not increment ii and therefore - * will not necessarily result in a 'true' return from readOverflow(). It does - * however subject 'ii' to soft bounds masking like the gI??() methods. - */ - ZT_INLINE uint8_t lI64(const int ii) const noexcept - { - const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; + /** + * Load a value at an index without advancing the index + * + * Note that unlike the rI??() methods this does not increment ii and therefore + * will not necessarily result in a 'true' return from readOverflow(). It does + * however subject 'ii' to soft bounds masking like the gI??() methods. + */ + ZT_INLINE uint8_t lI64(const int ii) const noexcept + { + const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - return ( - ((uint64_t)unsafeData[s] << 56U) | - ((uint64_t)unsafeData[s + 1] << 48U) | - ((uint64_t)unsafeData[s + 2] << 40U) | - ((uint64_t)unsafeData[s + 3] << 32U) | - ((uint64_t)unsafeData[s + 4] << 24U) | - ((uint64_t)unsafeData[s + 5] << 16U) | - ((uint64_t)unsafeData[s + 6] << 8U) | - (uint64_t)unsafeData[s + 7]); + return ( + ((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s + 1] << 48U) + | ((uint64_t)unsafeData[s + 2] << 40U) | ((uint64_t)unsafeData[s + 3] << 32U) + | ((uint64_t)unsafeData[s + 4] << 24U) | ((uint64_t)unsafeData[s + 5] << 16U) + | ((uint64_t)unsafeData[s + 6] << 8U) | (uint64_t)unsafeData[s + 7]); #else - return Utils::ntoh(*reinterpret_cast(unsafeData + s)); + return Utils::ntoh(*reinterpret_cast(unsafeData + s)); #endif - } + } - /** - * Write a byte - * - * @param ii Index value-result parameter (incremented by 1) - * @param n Byte - */ - ZT_INLINE void wI8(int &ii, const uint8_t n) noexcept - { - const int s = ii++; - unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n; - } + /** + * Write a byte + * + * @param ii Index value-result parameter (incremented by 1) + * @param n Byte + */ + ZT_INLINE void wI8(int& ii, const uint8_t n) noexcept + { + const int s = ii++; + unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n; + } - /** - * Write a 16-bit integer in big-endian byte order - * - * @param ii Index value-result parameter (incremented by 2) - * @param n Integer - */ - ZT_INLINE void wI16(int &ii, const uint16_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; - ii += 2; + /** + * Write a 16-bit integer in big-endian byte order + * + * @param ii Index value-result parameter (incremented by 2) + * @param n Integer + */ + ZT_INLINE void wI16(int& ii, const uint16_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + ii += 2; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 8U); - unsafeData[s + 1] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 8U); + unsafeData[s + 1] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * Write a 32-bit integer in big-endian byte order - * - * @param ii Index value-result parameter (incremented by 4) - * @param n Integer - */ - ZT_INLINE void wI32(int &ii, const uint32_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; - ii += 4; + /** + * Write a 32-bit integer in big-endian byte order + * + * @param ii Index value-result parameter (incremented by 4) + * @param n Integer + */ + ZT_INLINE void wI32(int& ii, const uint32_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + ii += 4; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 24U); - unsafeData[s + 1] = (uint8_t)(n >> 16U); - unsafeData[s + 2] = (uint8_t)(n >> 8U); - unsafeData[s + 3] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 24U); + unsafeData[s + 1] = (uint8_t)(n >> 16U); + unsafeData[s + 2] = (uint8_t)(n >> 8U); + unsafeData[s + 3] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * Write a 64-bit integer in big-endian byte order - * - * @param ii Index value-result parameter (incremented by 8) - * @param n Integer - */ - ZT_INLINE void wI64(int &ii, const uint64_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; - ii += 8; + /** + * Write a 64-bit integer in big-endian byte order + * + * @param ii Index value-result parameter (incremented by 8) + * @param n Integer + */ + ZT_INLINE void wI64(int& ii, const uint64_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + ii += 8; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 56U); - unsafeData[s + 1] = (uint8_t)(n >> 48U); - unsafeData[s + 2] = (uint8_t)(n >> 40U); - unsafeData[s + 3] = (uint8_t)(n >> 32U); - unsafeData[s + 4] = (uint8_t)(n >> 24U); - unsafeData[s + 5] = (uint8_t)(n >> 16U); - unsafeData[s + 6] = (uint8_t)(n >> 8U); - unsafeData[s + 7] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 56U); + unsafeData[s + 1] = (uint8_t)(n >> 48U); + unsafeData[s + 2] = (uint8_t)(n >> 40U); + unsafeData[s + 3] = (uint8_t)(n >> 32U); + unsafeData[s + 4] = (uint8_t)(n >> 24U); + unsafeData[s + 5] = (uint8_t)(n >> 16U); + unsafeData[s + 6] = (uint8_t)(n >> 8U); + unsafeData[s + 7] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * Write an object implementing the marshal interface - * - * @tparam T Object type - * @param ii Index value-result parameter (incremented by size of object) - * @param t Object to write - */ - template< typename T > - ZT_INLINE void wO(int &ii, T &t) noexcept - { - const int s = ii; - if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) { - int ms = t.marshal(unsafeData + s); - if (ms > 0) - ii += ms; - } else { - ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything - } - } + /** + * Write an object implementing the marshal interface + * + * @tparam T Object type + * @param ii Index value-result parameter (incremented by size of object) + * @param t Object to write + */ + template ZT_INLINE void wO(int& ii, T& t) noexcept + { + const int s = ii; + if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) { + int ms = t.marshal(unsafeData + s); + if (ms > 0) + ii += ms; + } + else { + ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything + } + } - /** - * Write a C-style null-terminated string (including the trailing zero) - * - * @param ii Index value-result parameter (incremented by length of string) - * @param s String to write (writes an empty string if this is NULL) - */ - ZT_INLINE void wS(int &ii, const char *s) noexcept - { - if (s) { - char c; - do { - c = *(s++); - wI8(ii, (uint8_t)c); - } while (c); - } else { - wI8(ii, 0); - } - } + /** + * Write a C-style null-terminated string (including the trailing zero) + * + * @param ii Index value-result parameter (incremented by length of string) + * @param s String to write (writes an empty string if this is NULL) + */ + ZT_INLINE void wS(int& ii, const char* s) noexcept + { + if (s) { + char c; + do { + c = *(s++); + wI8(ii, (uint8_t)c); + } while (c); + } + else { + wI8(ii, 0); + } + } - /** - * Write a byte array - * - * @param ii Index value-result parameter (incremented by len) - * @param bytes Bytes to write - * @param len Size of data in bytes - */ - ZT_INLINE void wB(int &ii, const void *const bytes, const unsigned int len) noexcept - { - const int s = ii; - if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) - Utils::copy(unsafeData + s, bytes, len); - } + /** + * Write a byte array + * + * @param ii Index value-result parameter (incremented by len) + * @param bytes Bytes to write + * @param len Size of data in bytes + */ + ZT_INLINE void wB(int& ii, const void* const bytes, const unsigned int len) noexcept + { + const int s = ii; + if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) + Utils::copy(unsafeData + s, bytes, len); + } - /** - * Write zeroes - * - * @param ii Index value-result parameter (incremented by len) - * @param len Number of zero bytes to write - */ - ZT_INLINE void wZ(int &ii, const unsigned int len) noexcept - { - const int s = ii; - if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) - Utils::zero(unsafeData + s, len); - } + /** + * Write zeroes + * + * @param ii Index value-result parameter (incremented by len) + * @param len Number of zero bytes to write + */ + ZT_INLINE void wZ(int& ii, const unsigned int len) noexcept + { + const int s = ii; + if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) + Utils::zero(unsafeData + s, len); + } - /** - * Write secure random bytes - * - * @param ii Index value-result parameter (incremented by len) - * @param len Number of random bytes to write - */ - ZT_INLINE void wR(int &ii, const unsigned int len) noexcept - { - const int s = ii; - if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) - Utils::getSecureRandom(unsafeData + s, len); - } + /** + * Write secure random bytes + * + * @param ii Index value-result parameter (incremented by len) + * @param len Number of random bytes to write + */ + ZT_INLINE void wR(int& ii, const unsigned int len) noexcept + { + const int s = ii; + if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) + Utils::getSecureRandom(unsafeData + s, len); + } - /** - * Store a byte without advancing the index - */ - ZT_INLINE void sI8(const int ii, const uint8_t n) noexcept - { - unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK] = n; - } + /** + * Store a byte without advancing the index + */ + ZT_INLINE void sI8(const int ii, const uint8_t n) noexcept + { + unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK] = n; + } - /** - * Store an integer without advancing the index - */ - ZT_INLINE void sI16(const int ii, const uint16_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + /** + * Store an integer without advancing the index + */ + ZT_INLINE void sI16(const int ii, const uint16_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 8U); - unsafeData[s + 1] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 8U); + unsafeData[s + 1] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * Store an integer without advancing the index - */ - ZT_INLINE void sI32(const int ii, const uint32_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + /** + * Store an integer without advancing the index + */ + ZT_INLINE void sI32(const int ii, const uint32_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 24U); - unsafeData[s + 1] = (uint8_t)(n >> 16U); - unsafeData[s + 2] = (uint8_t)(n >> 8U); - unsafeData[s + 3] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 24U); + unsafeData[s + 1] = (uint8_t)(n >> 16U); + unsafeData[s + 2] = (uint8_t)(n >> 8U); + unsafeData[s + 3] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * Store an integer without advancing the index - */ - ZT_INLINE void sI64(const int ii, const uint64_t n) noexcept - { - const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; + /** + * Store an integer without advancing the index + */ + ZT_INLINE void sI64(const int ii, const uint64_t n) noexcept + { + const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; #ifdef ZT_NO_UNALIGNED_ACCESS - unsafeData[s] = (uint8_t)(n >> 56U); - unsafeData[s + 1] = (uint8_t)(n >> 48U); - unsafeData[s + 2] = (uint8_t)(n >> 40U); - unsafeData[s + 3] = (uint8_t)(n >> 32U); - unsafeData[s + 4] = (uint8_t)(n >> 24U); - unsafeData[s + 5] = (uint8_t)(n >> 16U); - unsafeData[s + 6] = (uint8_t)(n >> 8U); - unsafeData[s + 7] = (uint8_t)n; + unsafeData[s] = (uint8_t)(n >> 56U); + unsafeData[s + 1] = (uint8_t)(n >> 48U); + unsafeData[s + 2] = (uint8_t)(n >> 40U); + unsafeData[s + 3] = (uint8_t)(n >> 32U); + unsafeData[s + 4] = (uint8_t)(n >> 24U); + unsafeData[s + 5] = (uint8_t)(n >> 16U); + unsafeData[s + 6] = (uint8_t)(n >> 8U); + unsafeData[s + 7] = (uint8_t)n; #else - *reinterpret_cast(unsafeData + s) = Utils::hton(n); + *reinterpret_cast(unsafeData + s) = Utils::hton(n); #endif - } + } - /** - * @return Capacity of this buffer (usable size of data.bytes) - */ - static constexpr unsigned int capacity() noexcept - { return ZT_BUF_MEM_SIZE; } + /** + * @return Capacity of this buffer (usable size of data.bytes) + */ + static constexpr unsigned int capacity() noexcept + { + return ZT_BUF_MEM_SIZE; + } -private: - volatile uintptr_t __nextInPool; - std::atomic< int > __refCount; + private: + volatile uintptr_t __nextInPool; + std::atomic __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/C25519.cpp b/core/C25519.cpp index bf5d0cca8..408c95e62 100644 --- a/core/C25519.cpp +++ b/core/C25519.cpp @@ -8,11 +8,12 @@ Derived from public domain code by D. J. Bernstein. // its original license. #include "C25519.hpp" + #include "SHA512.hpp" #include "Utils.hpp" #ifdef __WINDOWS__ -#pragma warning(disable: 4146) +#pragma warning(disable : 4146) #endif #ifdef __GNUC__ @@ -26,165 +27,130 @@ namespace { // -------------------------------------------------------------------------------------------------------------------- -#define crypto_uint32 uint32_t +#define crypto_uint32 uint32_t #define crypto_hash_sha512_BYTES 64 typedef uint8_t u8; typedef int32_t s32; typedef int64_t limb; -ZT_INLINE void fsum(limb *output,const limb *in) { - unsigned i; - for (i = 0; i < 10; i += 2) { - output[0+i] = output[0+i] + in[0+i]; - output[1+i] = output[1+i] + in[1+i]; - } +ZT_INLINE void fsum(limb* output, const limb* in) +{ + unsigned i; + for (i = 0; i < 10; i += 2) { + output[0 + i] = output[0 + i] + in[0 + i]; + output[1 + i] = output[1 + i] + in[1 + i]; + } } -ZT_INLINE void fdifference(limb *output,const limb *in) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] - output[i]; - } +ZT_INLINE void fdifference(limb* output, const limb* in) +{ + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] - output[i]; + } } -ZT_INLINE void fscalar_product(limb *output,const limb *in,const limb scalar) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] * scalar; - } +ZT_INLINE void fscalar_product(limb* output, const limb* in, const limb scalar) +{ + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] * scalar; + } } -void fproduct(limb *output,const limb *in2,const limb *in) { - output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); - output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + - ((limb) ((s32) in2[1])) * ((s32) in[0]); - output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[0]); - output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[0]); - output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + - 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[1])) + - ((limb) ((s32) in2[0])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[0]); - output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[0]); - output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[0]); - output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[0]); - output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[0]); - output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[0]); - output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[1])) + - ((limb) ((s32) in2[4])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[4]) + - ((limb) ((s32) in2[2])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[2]); - output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[2]); - output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[3])) + - ((limb) ((s32) in2[4])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[4]); - output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[6]) + - ((limb) ((s32) in2[5])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[4]); - output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + - ((limb) ((s32) in2[5])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[5])) + - ((limb) ((s32) in2[6])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[6]); - output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[7]) + - ((limb) ((s32) in2[6])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[6]); - output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[7])); - output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[8]); - output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); +void fproduct(limb* output, const limb* in2, const limb* in) +{ + output[0] = ((limb)((s32)in2[0])) * ((s32)in[0]); + output[1] = ((limb)((s32)in2[0])) * ((s32)in[1]) + ((limb)((s32)in2[1])) * ((s32)in[0]); + output[2] = 2 * ((limb)((s32)in2[1])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[2]) + + ((limb)((s32)in2[2])) * ((s32)in[0]); + output[3] = ((limb)((s32)in2[1])) * ((s32)in[2]) + ((limb)((s32)in2[2])) * ((s32)in[1]) + + ((limb)((s32)in2[0])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[0]); + output[4] = ((limb)((s32)in2[2])) * ((s32)in[2]) + + 2 * (((limb)((s32)in2[1])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[1])) + + ((limb)((s32)in2[0])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[0]); + output[5] = ((limb)((s32)in2[2])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[2]) + + ((limb)((s32)in2[1])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[1]) + + ((limb)((s32)in2[0])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[0]); + output[6] = 2 + * (((limb)((s32)in2[3])) * ((s32)in[3]) + ((limb)((s32)in2[1])) * ((s32)in[5]) + + ((limb)((s32)in2[5])) * ((s32)in[1])) + + ((limb)((s32)in2[2])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[2]) + + ((limb)((s32)in2[0])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[0]); + output[7] = ((limb)((s32)in2[3])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[3]) + + ((limb)((s32)in2[2])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[2]) + + ((limb)((s32)in2[1])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[1]) + + ((limb)((s32)in2[0])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[0]); + output[8] = ((limb)((s32)in2[4])) * ((s32)in[4]) + + 2 + * (((limb)((s32)in2[3])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[3]) + + ((limb)((s32)in2[1])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[1])) + + ((limb)((s32)in2[2])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[2]) + + ((limb)((s32)in2[0])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[0]); + output[9] = ((limb)((s32)in2[4])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[4]) + + ((limb)((s32)in2[3])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[3]) + + ((limb)((s32)in2[2])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[2]) + + ((limb)((s32)in2[1])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[1]) + + ((limb)((s32)in2[0])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[0]); + output[10] = 2 + * (((limb)((s32)in2[5])) * ((s32)in[5]) + ((limb)((s32)in2[3])) * ((s32)in[7]) + + ((limb)((s32)in2[7])) * ((s32)in[3]) + ((limb)((s32)in2[1])) * ((s32)in[9]) + + ((limb)((s32)in2[9])) * ((s32)in[1])) + + ((limb)((s32)in2[4])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[4]) + + ((limb)((s32)in2[2])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[2]); + output[11] = ((limb)((s32)in2[5])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[5]) + + ((limb)((s32)in2[4])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[4]) + + ((limb)((s32)in2[3])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[3]) + + ((limb)((s32)in2[2])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[2]); + output[12] = ((limb)((s32)in2[6])) * ((s32)in[6]) + + 2 + * (((limb)((s32)in2[5])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[5]) + + ((limb)((s32)in2[3])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[3])) + + ((limb)((s32)in2[4])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[4]); + output[13] = ((limb)((s32)in2[6])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[6]) + + ((limb)((s32)in2[5])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[5]) + + ((limb)((s32)in2[4])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[4]); + output[14] = 2 + * (((limb)((s32)in2[7])) * ((s32)in[7]) + ((limb)((s32)in2[5])) * ((s32)in[9]) + + ((limb)((s32)in2[9])) * ((s32)in[5])) + + ((limb)((s32)in2[6])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[6]); + output[15] = ((limb)((s32)in2[7])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[7]) + + ((limb)((s32)in2[6])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[6]); + output[16] = ((limb)((s32)in2[8])) * ((s32)in[8]) + + 2 * (((limb)((s32)in2[7])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[7])); + output[17] = ((limb)((s32)in2[8])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[8]); + output[18] = 2 * ((limb)((s32)in2[9])) * ((s32)in[9]); } -void freduce_degree(limb *output) { - output[8] += output[18] << 4; - output[8] += output[18] << 1; - output[8] += output[18]; - output[7] += output[17] << 4; - output[7] += output[17] << 1; - output[7] += output[17]; - output[6] += output[16] << 4; - output[6] += output[16] << 1; - output[6] += output[16]; - output[5] += output[15] << 4; - output[5] += output[15] << 1; - output[5] += output[15]; - output[4] += output[14] << 4; - output[4] += output[14] << 1; - output[4] += output[14]; - output[3] += output[13] << 4; - output[3] += output[13] << 1; - output[3] += output[13]; - output[2] += output[12] << 4; - output[2] += output[12] << 1; - output[2] += output[12]; - output[1] += output[11] << 4; - output[1] += output[11] << 1; - output[1] += output[11]; - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; +void freduce_degree(limb* output) +{ + output[8] += output[18] << 4; + output[8] += output[18] << 1; + output[8] += output[18]; + output[7] += output[17] << 4; + output[7] += output[17] << 1; + output[7] += output[17]; + output[6] += output[16] << 4; + output[6] += output[16] << 1; + output[6] += output[16]; + output[5] += output[15] << 4; + output[5] += output[15] << 1; + output[5] += output[15]; + output[4] += output[14] << 4; + output[4] += output[14] << 1; + output[4] += output[14]; + output[3] += output[13] << 4; + output[3] += output[13] << 1; + output[3] += output[13]; + output[2] += output[12] << 4; + output[2] += output[12] << 1; + output[2] += output[12]; + output[1] += output[11] << 4; + output[1] += output[11] << 1; + output[1] += output[11]; + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; } #if (-1 & 3) != 3 @@ -193,167 +159,161 @@ void freduce_degree(limb *output) { ZT_INLINE limb div_by_2_26(const limb v) { - /* High word of v; no shift needed. */ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x3ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 6; - /* Should return v / (1<<26) */ - return (v + roundoff) >> 26; + /* High word of v; no shift needed. */ + const uint32_t highword = (uint32_t)(((uint64_t)v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t)highword) >> 31; + /* Set to 0x3ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t)sign) >> 6; + /* Should return v / (1<<26) */ + return (v + roundoff) >> 26; } ZT_INLINE limb div_by_2_25(const limb v) { - /* High word of v; no shift needed*/ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x1ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 7; - /* Should return v / (1<<25) */ - return (v + roundoff) >> 25; + /* High word of v; no shift needed*/ + const uint32_t highword = (uint32_t)(((uint64_t)v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t)highword) >> 31; + /* Set to 0x1ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t)sign) >> 7; + /* Should return v / (1<<25) */ + return (v + roundoff) >> 25; } -void freduce_coefficients(limb *output) { - unsigned i; +void freduce_coefficients(limb* output) +{ + unsigned i; - output[10] = 0; + output[10] = 0; - for (i = 0; i < 10; i += 2) { - limb over = div_by_2_26(output[i]); - /* The entry condition (that |output[i]| < 280*2^54) means that over is, at - * most, 280*2^28 in the first iteration of this loop. This is added to the - * next limb and we can approximate the resulting bound of that limb by - * 281*2^54. */ - output[i] -= over << 26; - output[i+1] += over; + for (i = 0; i < 10; i += 2) { + limb over = div_by_2_26(output[i]); + /* The entry condition (that |output[i]| < 280*2^54) means that over is, at + * most, 280*2^28 in the first iteration of this loop. This is added to the + * next limb and we can approximate the resulting bound of that limb by + * 281*2^54. */ + output[i] -= over << 26; + output[i + 1] += over; - /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < - * 281*2^29. When this is added to the next limb, the resulting bound can - * be approximated as 281*2^54. - * - * For subsequent iterations of the loop, 281*2^54 remains a conservative - * bound and no overflow occurs. */ - over = div_by_2_25(output[i+1]); - output[i+1] -= over << 25; - output[i+2] += over; - } - /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; + /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < + * 281*2^29. When this is added to the next limb, the resulting bound can + * be approximated as 281*2^54. + * + * For subsequent iterations of the loop, 281*2^54 remains a conservative + * bound and no overflow occurs. */ + over = div_by_2_25(output[i + 1]); + output[i + 1] -= over << 25; + output[i + 2] += over; + } + /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; - output[10] = 0; + output[10] = 0; - /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 - * So |over| will be no more than 2^16. */ - { - limb over = div_by_2_26(output[0]); - output[0] -= over << 26; - output[1] += over; - } + /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 + * So |over| will be no more than 2^16. */ + { + limb over = div_by_2_26(output[0]); + output[0] -= over << 26; + output[1] += over; + } - /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The - * bound on |output[1]| is sufficient to meet our needs. */ + /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The + * bound on |output[1]| is sufficient to meet our needs. */ } -ZT_INLINE void fmul(limb *output,const limb *in,const limb *in2) { - limb t[19]; - fproduct(t, in, in2); - /* |t[i]| < 14*2^54 */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - Utils::copy(output,t); +ZT_INLINE void fmul(limb* output, const limb* in, const limb* in2) +{ + limb t[19]; + fproduct(t, in, in2); + /* |t[i]| < 14*2^54 */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + Utils::copy(output, t); } -void fsquare_inner(limb *output, const limb *in) { - output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); - output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); - output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + - ((limb) ((s32) in[0])) * ((s32) in[2])); - output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + - ((limb) ((s32) in[0])) * ((s32) in[3])); - output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + - 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + - 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); - output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + - ((limb) ((s32) in[1])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[5])); - output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + - ((limb) ((s32) in[2])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[6]) + - 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); - output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + - ((limb) ((s32) in[2])) * ((s32) in[5]) + - ((limb) ((s32) in[1])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[7])); - output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[5]))); - output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + - ((limb) ((s32) in[3])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[8]) + - ((limb) ((s32) in[0])) * ((s32) in[9])); - output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + - ((limb) ((s32) in[4])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[9]))); - output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + - ((limb) ((s32) in[4])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[8]) + - ((limb) ((s32) in[2])) * ((s32) in[9])); - output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[9]))); - output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + - ((limb) ((s32) in[5])) * ((s32) in[8]) + - ((limb) ((s32) in[4])) * ((s32) in[9])); - output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + - ((limb) ((s32) in[6])) * ((s32) in[8]) + - 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); - output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + - ((limb) ((s32) in[6])) * ((s32) in[9])); - output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + - 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); - output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); - output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); +void fsquare_inner(limb* output, const limb* in) +{ + output[0] = ((limb)((s32)in[0])) * ((s32)in[0]); + output[1] = 2 * ((limb)((s32)in[0])) * ((s32)in[1]); + output[2] = 2 * (((limb)((s32)in[1])) * ((s32)in[1]) + ((limb)((s32)in[0])) * ((s32)in[2])); + output[3] = 2 * (((limb)((s32)in[1])) * ((s32)in[2]) + ((limb)((s32)in[0])) * ((s32)in[3])); + output[4] = ((limb)((s32)in[2])) * ((s32)in[2]) + 4 * ((limb)((s32)in[1])) * ((s32)in[3]) + + 2 * ((limb)((s32)in[0])) * ((s32)in[4]); + output[5] = 2 + * (((limb)((s32)in[2])) * ((s32)in[3]) + ((limb)((s32)in[1])) * ((s32)in[4]) + + ((limb)((s32)in[0])) * ((s32)in[5])); + output[6] = 2 + * (((limb)((s32)in[3])) * ((s32)in[3]) + ((limb)((s32)in[2])) * ((s32)in[4]) + + ((limb)((s32)in[0])) * ((s32)in[6]) + 2 * ((limb)((s32)in[1])) * ((s32)in[5])); + output[7] = 2 + * (((limb)((s32)in[3])) * ((s32)in[4]) + ((limb)((s32)in[2])) * ((s32)in[5]) + + ((limb)((s32)in[1])) * ((s32)in[6]) + ((limb)((s32)in[0])) * ((s32)in[7])); + output[8] = ((limb)((s32)in[4])) * ((s32)in[4]) + + 2 + * (((limb)((s32)in[2])) * ((s32)in[6]) + ((limb)((s32)in[0])) * ((s32)in[8]) + + 2 * (((limb)((s32)in[1])) * ((s32)in[7]) + ((limb)((s32)in[3])) * ((s32)in[5]))); + output[9] = 2 + * (((limb)((s32)in[4])) * ((s32)in[5]) + ((limb)((s32)in[3])) * ((s32)in[6]) + + ((limb)((s32)in[2])) * ((s32)in[7]) + ((limb)((s32)in[1])) * ((s32)in[8]) + + ((limb)((s32)in[0])) * ((s32)in[9])); + output[10] = 2 + * (((limb)((s32)in[5])) * ((s32)in[5]) + ((limb)((s32)in[4])) * ((s32)in[6]) + + ((limb)((s32)in[2])) * ((s32)in[8]) + + 2 * (((limb)((s32)in[3])) * ((s32)in[7]) + ((limb)((s32)in[1])) * ((s32)in[9]))); + output[11] = 2 + * (((limb)((s32)in[5])) * ((s32)in[6]) + ((limb)((s32)in[4])) * ((s32)in[7]) + + ((limb)((s32)in[3])) * ((s32)in[8]) + ((limb)((s32)in[2])) * ((s32)in[9])); + output[12] = ((limb)((s32)in[6])) * ((s32)in[6]) + + 2 + * (((limb)((s32)in[4])) * ((s32)in[8]) + + 2 * (((limb)((s32)in[5])) * ((s32)in[7]) + ((limb)((s32)in[3])) * ((s32)in[9]))); + output[13] = 2 + * (((limb)((s32)in[6])) * ((s32)in[7]) + ((limb)((s32)in[5])) * ((s32)in[8]) + + ((limb)((s32)in[4])) * ((s32)in[9])); + output[14] = 2 + * (((limb)((s32)in[7])) * ((s32)in[7]) + ((limb)((s32)in[6])) * ((s32)in[8]) + + 2 * ((limb)((s32)in[5])) * ((s32)in[9])); + output[15] = 2 * (((limb)((s32)in[7])) * ((s32)in[8]) + ((limb)((s32)in[6])) * ((s32)in[9])); + output[16] = ((limb)((s32)in[8])) * ((s32)in[8]) + 4 * ((limb)((s32)in[7])) * ((s32)in[9]); + output[17] = 2 * ((limb)((s32)in[8])) * ((s32)in[9]); + output[18] = 2 * ((limb)((s32)in[9])) * ((s32)in[9]); } -ZT_INLINE void fsquare(limb *output,const limb *in) { - limb t[19]; - fsquare_inner(t, in); - /* |t[i]| < 14*2^54 because the largest product of two limbs will be < - * 2^(27+27) and fsquare_inner adds together, at most, 14 of those - * products. */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - Utils::copy(output,t); +ZT_INLINE void fsquare(limb* output, const limb* in) +{ + limb t[19]; + fsquare_inner(t, in); + /* |t[i]| < 14*2^54 because the largest product of two limbs will be < + * 2^(27+27) and fsquare_inner adds together, at most, 14 of those + * products. */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + Utils::copy(output, t); } -ZT_INLINE void fexpand(limb *output,const u8 *input) { -#define F(n,start,shift,mask) \ - output[n] = ((((limb) input[start + 0]) | \ - ((limb) input[start + 1]) << 8 | \ - ((limb) input[start + 2]) << 16 | \ - ((limb) input[start + 3]) << 24) >> shift) & mask; - F(0, 0, 0, 0x3ffffff); - F(1, 3, 2, 0x1ffffff); - F(2, 6, 3, 0x3ffffff); - F(3, 9, 5, 0x1ffffff); - F(4, 12, 6, 0x3ffffff); - F(5, 16, 0, 0x1ffffff); - F(6, 19, 1, 0x3ffffff); - F(7, 22, 3, 0x1ffffff); - F(8, 25, 4, 0x3ffffff); - F(9, 28, 6, 0x1ffffff); +ZT_INLINE void fexpand(limb* output, const u8* input) +{ +#define F(n, start, shift, mask) \ + output[n] = ((((limb)input[start + 0]) | ((limb)input[start + 1]) << 8 | ((limb)input[start + 2]) << 16 \ + | ((limb)input[start + 3]) << 24) \ + >> shift) \ + & mask; + F(0, 0, 0, 0x3ffffff); + F(1, 3, 2, 0x1ffffff); + F(2, 6, 3, 0x3ffffff); + F(3, 9, 5, 0x1ffffff); + F(4, 12, 6, 0x3ffffff); + F(5, 16, 0, 0x1ffffff); + F(6, 19, 1, 0x3ffffff); + F(7, 22, 3, 0x1ffffff); + F(8, 25, 4, 0x3ffffff); + F(9, 28, 6, 0x1ffffff); #undef F } @@ -361,2146 +321,3116 @@ ZT_INLINE void fexpand(limb *output,const u8 *input) { #error "This code only works when >> does sign-extension on negative numbers" #endif -ZT_INLINE s32 s32_eq(s32 a,s32 b) { - a = ~(a ^ b); - a &= a << 16; - a &= a << 8; - a &= a << 4; - a &= a << 2; - a &= a << 1; - return a >> 31; +ZT_INLINE s32 s32_eq(s32 a, s32 b) +{ + a = ~(a ^ b); + a &= a << 16; + a &= a << 8; + a &= a << 4; + a &= a << 2; + a &= a << 1; + return a >> 31; } -ZT_INLINE s32 s32_gte(s32 a,s32 b) { - a -= b; - /* a >= 0 iff a >= b. */ - return ~(a >> 31); +ZT_INLINE s32 s32_gte(s32 a, s32 b) +{ + a -= b; + /* a >= 0 iff a >= b. */ + return ~(a >> 31); } -void fcontract(u8 *output,limb *input_limbs) { - int i; - int j; - s32 input[10]; - s32 mask; +void fcontract(u8* output, limb* input_limbs) +{ + int i; + int j; + s32 input[10]; + s32 mask; - for (i = 0; i < 10; i++) { - input[i] = input_limbs[i]; - } - for (j = 0; j < 2; ++j) { - for (i = 0; i < 9; ++i) { - if ((i & 1) == 1) { - const s32 mm = input[i] >> 31; - const s32 carry = -((input[i] & mm) >> 25); - input[i] = input[i] + (carry << 25); - input[i+1] = input[i+1] - carry; - } else { - const s32 mm = input[i] >> 31; - const s32 carry = -((input[i] & mm) >> 26); - input[i] = input[i] + (carry << 26); - input[i+1] = input[i+1] - carry; - } - } - { - const s32 mm = input[9] >> 31; - const s32 carry = -((input[9] & mm) >> 25); - input[9] = input[9] + (carry << 25); - input[0] = input[0] - (carry * 19); - } - } - { - const s32 mm = input[0] >> 31; - const s32 carry = -((input[0] & mm) >> 26); - input[0] = input[0] + (carry << 26); - input[1] = input[1] - carry; - } - for (j = 0; j < 2; j++) { - for (i = 0; i < 9; i++) { - if ((i & 1) == 1) { - const s32 carry = input[i] >> 25; - input[i] &= 0x1ffffff; - input[i+1] += carry; - } else { - const s32 carry = input[i] >> 26; - input[i] &= 0x3ffffff; - input[i+1] += carry; - } - } - { - const s32 carry = input[9] >> 25; - input[9] &= 0x1ffffff; - input[0] += 19*carry; - } - } - mask = s32_gte(input[0], 0x3ffffed); - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - mask &= s32_eq(input[i], 0x1ffffff); - } else { - mask &= s32_eq(input[i], 0x3ffffff); - } - } - input[0] -= mask & 0x3ffffed; - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - input[i] -= mask & 0x1ffffff; - } else { - input[i] -= mask & 0x3ffffff; - } - } + for (i = 0; i < 10; i++) { + input[i] = input_limbs[i]; + } + for (j = 0; j < 2; ++j) { + for (i = 0; i < 9; ++i) { + if ((i & 1) == 1) { + const s32 mm = input[i] >> 31; + const s32 carry = -((input[i] & mm) >> 25); + input[i] = input[i] + (carry << 25); + input[i + 1] = input[i + 1] - carry; + } + else { + const s32 mm = input[i] >> 31; + const s32 carry = -((input[i] & mm) >> 26); + input[i] = input[i] + (carry << 26); + input[i + 1] = input[i + 1] - carry; + } + } + { + const s32 mm = input[9] >> 31; + const s32 carry = -((input[9] & mm) >> 25); + input[9] = input[9] + (carry << 25); + input[0] = input[0] - (carry * 19); + } + } + { + const s32 mm = input[0] >> 31; + const s32 carry = -((input[0] & mm) >> 26); + input[0] = input[0] + (carry << 26); + input[1] = input[1] - carry; + } + for (j = 0; j < 2; j++) { + for (i = 0; i < 9; i++) { + if ((i & 1) == 1) { + const s32 carry = input[i] >> 25; + input[i] &= 0x1ffffff; + input[i + 1] += carry; + } + else { + const s32 carry = input[i] >> 26; + input[i] &= 0x3ffffff; + input[i + 1] += carry; + } + } + { + const s32 carry = input[9] >> 25; + input[9] &= 0x1ffffff; + input[0] += 19 * carry; + } + } + mask = s32_gte(input[0], 0x3ffffed); + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + mask &= s32_eq(input[i], 0x1ffffff); + } + else { + mask &= s32_eq(input[i], 0x3ffffff); + } + } + input[0] -= mask & 0x3ffffed; + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + input[i] -= mask & 0x1ffffff; + } + else { + input[i] -= mask & 0x3ffffff; + } + } - input[1] <<= 2; - input[2] <<= 3; - input[3] <<= 5; - input[4] <<= 6; - input[6] <<= 1; - input[7] <<= 3; - input[8] <<= 4; - input[9] <<= 6; -#define F(i, s) \ - output[s+0] |= input[i] & 0xff; \ - output[s+1] = (input[i] >> 8) & 0xff; \ - output[s+2] = (input[i] >> 16) & 0xff; \ - output[s+3] = (input[i] >> 24) & 0xff; - output[0] = 0; - output[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); + input[1] <<= 2; + input[2] <<= 3; + input[3] <<= 5; + input[4] <<= 6; + input[6] <<= 1; + input[7] <<= 3; + input[8] <<= 4; + input[9] <<= 6; +#define F(i, s) \ + output[s + 0] |= input[i] & 0xff; \ + output[s + 1] = (input[i] >> 8) & 0xff; \ + output[s + 2] = (input[i] >> 16) & 0xff; \ + output[s + 3] = (input[i] >> 24) & 0xff; + output[0] = 0; + output[16] = 0; + F(0, 0); + F(1, 3); + F(2, 6); + F(3, 9); + F(4, 12); + F(5, 16); + F(6, 19); + F(7, 22); + F(8, 25); + F(9, 28); #undef F } -void fmonty(limb *x2,limb *z2, /* output 2Q */ - limb *x3,limb *z3, /* output Q + Q' */ - limb *x,limb *z, /* input Q */ - limb *xprime,limb *zprime, /* input Q' */ - const limb *qmqp /* input Q - Q' */) { - limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], - zzprime[19], zzzprime[19], xxxprime[19]; - - Utils::copy<10 * sizeof(limb)>(origx,x); - fsum(x, z); - /* |x[i]| < 2^27 */ - fdifference(z, origx); /* does x - z */ - /* |z[i]| < 2^27 */ - - Utils::copy(origxprime, xprime); - fsum(xprime, zprime); - /* |xprime[i]| < 2^27 */ - fdifference(zprime, origxprime); - /* |zprime[i]| < 2^27 */ - fproduct(xxprime, xprime, z); - /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < - * 2^(27+27) and fproduct adds together, at most, 14 of those products. - * (Approximating that to 2^58 doesn't work out.) */ - fproduct(zzprime, x, zprime); - /* |zzprime[i]| < 14*2^54 */ - freduce_degree(xxprime); - freduce_coefficients(xxprime); - /* |xxprime[i]| < 2^26 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - Utils::copy(origxprime,xxprime); - fsum(xxprime, zzprime); - /* |xxprime[i]| < 2^27 */ - fdifference(zzprime, origxprime); - /* |zzprime[i]| < 2^27 */ - fsquare(xxxprime, xxprime); - /* |xxxprime[i]| < 2^26 */ - fsquare(zzzprime, zzprime); - /* |zzzprime[i]| < 2^26 */ - fproduct(zzprime, zzzprime, qmqp); - /* |zzprime[i]| < 14*2^52 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - Utils::copy(x3,xxxprime); - Utils::copy(z3,zzprime); - - fsquare(xx, x); - /* |xx[i]| < 2^26 */ - fsquare(zz, z); - /* |zz[i]| < 2^26 */ - fproduct(x2, xx, zz); - /* |x2[i]| < 14*2^52 */ - freduce_degree(x2); - freduce_coefficients(x2); - /* |x2[i]| < 2^26 */ - fdifference(zz, xx); // does zz = xx - zz - /* |zz[i]| < 2^27 */ - Utils::zero(zzz + 10); - fscalar_product(zzz, zz, 121665); - /* |zzz[i]| < 2^(27+17) */ - /* No need to call freduce_degree here: - fscalar_product doesn't increase the degree of its input. */ - freduce_coefficients(zzz); - /* |zzz[i]| < 2^26 */ - fsum(zzz, xx); - /* |zzz[i]| < 2^27 */ - fproduct(z2, zz, zzz); - /* |z2[i]| < 14*2^(26+27) */ - freduce_degree(z2); - freduce_coefficients(z2); - /* |z2|i| < 2^26 */ -} - -ZT_INLINE void swap_conditional(limb a[19],limb b[19],limb iswap) { - unsigned i; - const s32 swap = (s32) -iswap; - - for (i = 0; i < 10; ++i) { - const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); - a[i] = ((s32)a[i]) ^ x; - b[i] = ((s32)b[i]) ^ x; - } -} - -void cmult(limb *resultx,limb *resultz,const u8 *n,const limb *q) { - limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; - limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; - limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; - limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; - - unsigned i, j; - - Utils::copy(nqpqx,q); - - for (i = 0; i < 32; ++i) { - u8 byte = n[31 - i]; - for (j = 0; j < 8; ++j) { - const limb bit = byte >> 7; - - swap_conditional(nqx, nqpqx, bit); - swap_conditional(nqz, nqpqz, bit); - fmonty(nqx2, nqz2, - nqpqx2, nqpqz2, - nqx, nqz, - nqpqx, nqpqz, - q); - swap_conditional(nqx2, nqpqx2, bit); - swap_conditional(nqz2, nqpqz2, bit); - - t = nqx; - nqx = nqx2; - nqx2 = t; - t = nqz; - nqz = nqz2; - nqz2 = t; - t = nqpqx; - nqpqx = nqpqx2; - nqpqx2 = t; - t = nqpqz; - nqpqz = nqpqz2; - nqpqz2 = t; - - byte <<= 1; - } - } - - Utils::copy(resultx,nqx); - Utils::copy(resultz,nqz); -} - -ZT_INLINE void crecip(limb *out,const limb *z) { - limb z2[10]; - limb z9[10]; - limb z11[10]; - limb z2_5_0[10]; - limb z2_10_0[10]; - limb z2_20_0[10]; - limb z2_50_0[10]; - limb z2_100_0[10]; - limb t0[10]; - limb t1[10]; - int i; - - /* 2 */ fsquare(z2,z); - /* 4 */ fsquare(t1,z2); - /* 8 */ fsquare(t0,t1); - /* 9 */ fmul(z9,t0,z); - /* 11 */ fmul(z11,z9,z2); - /* 22 */ fsquare(t0,z11); - /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); - /* 2^7 - 2^2 */ fsquare(t1,t0); - /* 2^8 - 2^3 */ fsquare(t0,t1); - /* 2^9 - 2^4 */ fsquare(t1,t0); - /* 2^10 - 2^5 */ fsquare(t0,t1); - /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); - /* 2^12 - 2^2 */ fsquare(t1,t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); - /* 2^22 - 2^2 */ fsquare(t1,t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ fsquare(t1,t0); - /* 2^42 - 2^2 */ fsquare(t0,t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); - /* 2^52 - 2^2 */ fsquare(t1,t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); - /* 2^102 - 2^2 */ fsquare(t0,t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ fsquare(t0,t1); - /* 2^202 - 2^2 */ fsquare(t1,t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ fsquare(t1,t0); - /* 2^252 - 2^2 */ fsquare(t0,t1); - /* 2^253 - 2^3 */ fsquare(t1,t0); - /* 2^254 - 2^4 */ fsquare(t0,t1); - /* 2^255 - 2^5 */ fsquare(t1,t0); - /* 2^255 - 21 */ fmul(out,t1,z11); -} - -void crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoint) +void fmonty( + limb* x2, + limb* z2, /* output 2Q */ + limb* x3, + limb* z3, /* output Q + Q' */ + limb* x, + limb* z, /* input Q */ + limb* xprime, + limb* zprime, /* input Q' */ + const limb* qmqp /* input Q - Q' */) { - limb bp[10], x[10], z[11], zmone[10]; - uint8_t e[32]; - int i; + limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], zzprime[19], zzzprime[19], xxxprime[19]; - for (i = 0; i < 32; ++i) e[i] = secret[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; + Utils::copy<10 * sizeof(limb)>(origx, x); + fsum(x, z); + /* |x[i]| < 2^27 */ + fdifference(z, origx); /* does x - z */ + /* |z[i]| < 2^27 */ - fexpand(bp, basepoint); - cmult(x, z, e, bp); - crecip(zmone, z); - fmul(z, x, zmone); - fcontract(mypublic, z); + Utils::copy(origxprime, xprime); + fsum(xprime, zprime); + /* |xprime[i]| < 2^27 */ + fdifference(zprime, origxprime); + /* |zprime[i]| < 2^27 */ + fproduct(xxprime, xprime, z); + /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < + * 2^(27+27) and fproduct adds together, at most, 14 of those products. + * (Approximating that to 2^58 doesn't work out.) */ + fproduct(zzprime, x, zprime); + /* |zzprime[i]| < 14*2^54 */ + freduce_degree(xxprime); + freduce_coefficients(xxprime); + /* |xxprime[i]| < 2^26 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + Utils::copy(origxprime, xxprime); + fsum(xxprime, zzprime); + /* |xxprime[i]| < 2^27 */ + fdifference(zzprime, origxprime); + /* |zzprime[i]| < 2^27 */ + fsquare(xxxprime, xxprime); + /* |xxxprime[i]| < 2^26 */ + fsquare(zzzprime, zzprime); + /* |zzzprime[i]| < 2^26 */ + fproduct(zzprime, zzzprime, qmqp); + /* |zzprime[i]| < 14*2^52 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + Utils::copy(x3, xxxprime); + Utils::copy(z3, zzprime); + + fsquare(xx, x); + /* |xx[i]| < 2^26 */ + fsquare(zz, z); + /* |zz[i]| < 2^26 */ + fproduct(x2, xx, zz); + /* |x2[i]| < 14*2^52 */ + freduce_degree(x2); + freduce_coefficients(x2); + /* |x2[i]| < 2^26 */ + fdifference(zz, xx); // does zz = xx - zz + /* |zz[i]| < 2^27 */ + Utils::zero(zzz + 10); + fscalar_product(zzz, zz, 121665); + /* |zzz[i]| < 2^(27+17) */ + /* No need to call freduce_degree here: + fscalar_product doesn't increase the degree of its input. */ + freduce_coefficients(zzz); + /* |zzz[i]| < 2^26 */ + fsum(zzz, xx); + /* |zzz[i]| < 2^27 */ + fproduct(z2, zz, zzz); + /* |z2[i]| < 14*2^(26+27) */ + freduce_degree(z2); + freduce_coefficients(z2); + /* |z2|i| < 2^26 */ } -static const unsigned char base[32] = {9}; -ZT_INLINE void crypto_scalarmult_base(unsigned char *q,const unsigned char *n) { crypto_scalarmult(q,n,base); } +ZT_INLINE void swap_conditional(limb a[19], limb b[19], limb iswap) +{ + unsigned i; + const s32 swap = (s32)-iswap; + + for (i = 0; i < 10; ++i) { + const s32 x = swap & (((s32)a[i]) ^ ((s32)b[i])); + a[i] = ((s32)a[i]) ^ x; + b[i] = ((s32)b[i]) ^ x; + } +} + +void cmult(limb* resultx, limb* resultz, const u8* n, const limb* q) +{ + limb a[19] = { 0 }, b[19] = { 1 }, c[19] = { 1 }, d[19] = { 0 }; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[19] = { 0 }, f[19] = { 1 }, g[19] = { 0 }, h[19] = { 1 }; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + Utils::copy(nqpqx, q); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, nqpqx2, nqpqz2, nqx, nqz, nqpqx, nqpqz, q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + Utils::copy(resultx, nqx); + Utils::copy(resultz, nqz); +} + +ZT_INLINE void crecip(limb* out, const limb* z) +{ + limb z2[10]; + limb z9[10]; + limb z11[10]; + limb z2_5_0[10]; + limb z2_10_0[10]; + limb z2_20_0[10]; + limb z2_50_0[10]; + limb z2_100_0[10]; + limb t0[10]; + limb t1[10]; + int i; + + /* 2 */ fsquare(z2, z); + /* 4 */ fsquare(t1, z2); + /* 8 */ fsquare(t0, t1); + /* 9 */ fmul(z9, t0, z); + /* 11 */ fmul(z11, z9, z2); + /* 22 */ fsquare(t0, z11); + /* 2^5 - 2^0 = 31 */ fmul(z2_5_0, t0, z9); + + /* 2^6 - 2^1 */ fsquare(t0, z2_5_0); + /* 2^7 - 2^2 */ fsquare(t1, t0); + /* 2^8 - 2^3 */ fsquare(t0, t1); + /* 2^9 - 2^4 */ fsquare(t1, t0); + /* 2^10 - 2^5 */ fsquare(t0, t1); + /* 2^10 - 2^0 */ fmul(z2_10_0, t0, z2_5_0); + + /* 2^11 - 2^1 */ fsquare(t0, z2_10_0); + /* 2^12 - 2^2 */ fsquare(t1, t0); + /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^20 - 2^0 */ fmul(z2_20_0, t1, z2_10_0); + + /* 2^21 - 2^1 */ fsquare(t0, z2_20_0); + /* 2^22 - 2^2 */ fsquare(t1, t0); + /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^40 - 2^0 */ fmul(t0, t1, z2_20_0); + + /* 2^41 - 2^1 */ fsquare(t1, t0); + /* 2^42 - 2^2 */ fsquare(t0, t1); + /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { + fsquare(t1, t0); + fsquare(t0, t1); + } + /* 2^50 - 2^0 */ fmul(z2_50_0, t0, z2_10_0); + + /* 2^51 - 2^1 */ fsquare(t0, z2_50_0); + /* 2^52 - 2^2 */ fsquare(t1, t0); + /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^100 - 2^0 */ fmul(z2_100_0, t1, z2_50_0); + + /* 2^101 - 2^1 */ fsquare(t1, z2_100_0); + /* 2^102 - 2^2 */ fsquare(t0, t1); + /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { + fsquare(t1, t0); + fsquare(t0, t1); + } + /* 2^200 - 2^0 */ fmul(t1, t0, z2_100_0); + + /* 2^201 - 2^1 */ fsquare(t0, t1); + /* 2^202 - 2^2 */ fsquare(t1, t0); + /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^250 - 2^0 */ fmul(t0, t1, z2_50_0); + + /* 2^251 - 2^1 */ fsquare(t1, t0); + /* 2^252 - 2^2 */ fsquare(t0, t1); + /* 2^253 - 2^3 */ fsquare(t1, t0); + /* 2^254 - 2^4 */ fsquare(t0, t1); + /* 2^255 - 2^5 */ fsquare(t1, t0); + /* 2^255 - 21 */ fmul(out, t1, z11); +} + +void crypto_scalarmult(u8* mypublic, const u8* secret, const u8* basepoint) +{ + limb bp[10], x[10], z[11], zmone[10]; + uint8_t e[32]; + int i; + + for (i = 0; i < 32; ++i) + e[i] = secret[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(mypublic, z); +} + +static const unsigned char base[32] = { 9 }; +ZT_INLINE void crypto_scalarmult_base(unsigned char* q, const unsigned char* n) +{ + crypto_scalarmult(q, n, base); +} // -------------------------------------------------------------------------------------------------------------------- // Ed25519 ref from: http://bench.cr.yp.to/supercop.html -typedef struct -{ - crypto_uint32 v[32]; -} -fe25519; +typedef struct { + crypto_uint32 v[32]; +} fe25519; -typedef struct -{ - crypto_uint32 v[32]; -} -sc25519; +typedef struct { + crypto_uint32 v[32]; +} sc25519; -typedef struct -{ - crypto_uint32 v[16]; -} -shortsc25519; +typedef struct { + crypto_uint32 v[16]; +} shortsc25519; -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; - fe25519 t; +typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; + fe25519 t; } ge25519; #define ge25519_p3 ge25519 -typedef struct -{ - fe25519 x; - fe25519 z; - fe25519 y; - fe25519 t; +typedef struct { + fe25519 x; + fe25519 z; + fe25519 y; + fe25519 t; } ge25519_p1p1; -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; +typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; } ge25519_p2; -typedef struct -{ - fe25519 x; - fe25519 y; +typedef struct { + fe25519 x; + fe25519 y; } ge25519_aff; -void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); +void fe25519_sub(fe25519* r, const fe25519* x, const fe25519* y); -ZT_INLINE crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ +ZT_INLINE crypto_uint32 equal(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ { - crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */ - x -= 1; /* 4294967295: yes; 0..65534: no */ - x >>= 31; /* 1: yes; 0: no */ - return x; + crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */ + x -= 1; /* 4294967295: yes; 0..65534: no */ + x >>= 31; /* 1: yes; 0: no */ + return x; } -ZT_INLINE crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ +ZT_INLINE crypto_uint32 ge(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ { - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */ - x >>= 31; /* 0: yes; 1: no */ - x ^= 1; /* 1: yes; 0: no */ - return x; + unsigned int x = a; + x -= (unsigned int)b; /* 0..65535: yes; 4294901761..4294967295: no */ + x >>= 31; /* 0: yes; 1: no */ + x ^= 1; /* 1: yes; 0: no */ + return x; } -ZT_INLINE crypto_uint32 times19(crypto_uint32 a) { return (a << 4) + (a << 1) + a; } -ZT_INLINE crypto_uint32 times38(crypto_uint32 a) { return (a << 5) + (a << 2) + (a << 1); } - -void reduce_add_sub(fe25519 *r) +ZT_INLINE crypto_uint32 times19(crypto_uint32 a) { - int i,rep; - for(rep=0;rep<4;rep++) - { - crypto_uint32 t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) - { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } + return (a << 4) + (a << 1) + a; +} +ZT_INLINE crypto_uint32 times38(crypto_uint32 a) +{ + return (a << 5) + (a << 2) + (a << 1); } -ZT_INLINE void reduce_mul(fe25519 *r) +void reduce_add_sub(fe25519* r) { - int i,rep; - for(rep=0;rep<2;rep++) - { - crypto_uint32 t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) - { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } + int i, rep; + for (rep = 0; rep < 4; rep++) { + crypto_uint32 t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for (i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i + 1] += t; + r->v[i] &= 255; + } + } } -void fe25519_freeze(fe25519 *r) +ZT_INLINE void reduce_mul(fe25519* r) { - int i; - crypto_uint32 mm = equal(r->v[31],127); - for(i=30;i>0;i--) - mm &= equal(r->v[i],255); - mm &= ge(r->v[0],237); - - mm = -mm; - - r->v[31] -= mm&127; - for(i=30;i>0;i--) - r->v[i] -= mm&255; - r->v[0] -= mm&237; + int i, rep; + for (rep = 0; rep < 2; rep++) { + crypto_uint32 t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for (i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i + 1] += t; + r->v[i] &= 255; + } + } } -ZT_INLINE void fe25519_unpack(fe25519 *r,const unsigned char x[32]) +void fe25519_freeze(fe25519* r) { - int i; - for(i=0;i<32;i++) r->v[i] = x[i]; - r->v[31] &= 127; + int i; + crypto_uint32 mm = equal(r->v[31], 127); + for (i = 30; i > 0; i--) + mm &= equal(r->v[i], 255); + mm &= ge(r->v[0], 237); + + mm = -mm; + + r->v[31] -= mm & 127; + for (i = 30; i > 0; i--) + r->v[i] -= mm & 255; + r->v[0] -= mm & 237; } -ZT_INLINE void fe25519_pack(unsigned char r[32],const fe25519 *x) +ZT_INLINE void fe25519_unpack(fe25519* r, const unsigned char x[32]) { - int i; - fe25519 y = *x; - fe25519_freeze(&y); - for(i=0;i<32;i++) - r[i] = y.v[i]; + int i; + for (i = 0; i < 32; i++) + r->v[i] = x[i]; + r->v[31] &= 127; } -ZT_INLINE int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) +ZT_INLINE void fe25519_pack(unsigned char r[32], const fe25519* x) { - int i; - fe25519 t1 = *x; - fe25519 t2 = *y; - fe25519_freeze(&t1); - fe25519_freeze(&t2); - for(i=0;i<32;i++) - if(t1.v[i] != t2.v[i]) return 0; - return 1; + int i; + fe25519 y = *x; + fe25519_freeze(&y); + for (i = 0; i < 32; i++) + r[i] = y.v[i]; } -ZT_INLINE void fe25519_cmov(fe25519 *r,const fe25519 *x,unsigned char b) +ZT_INLINE int fe25519_iseq_vartime(const fe25519* x, const fe25519* y) { - int i; - crypto_uint32 mask = b; - mask = -mask; - for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]); + int i; + fe25519 t1 = *x; + fe25519 t2 = *y; + fe25519_freeze(&t1); + fe25519_freeze(&t2); + for (i = 0; i < 32; i++) + if (t1.v[i] != t2.v[i]) + return 0; + return 1; } -ZT_INLINE unsigned char fe25519_getparity(const fe25519 *x) +ZT_INLINE void fe25519_cmov(fe25519* r, const fe25519* x, unsigned char b) { - fe25519 t = *x; - fe25519_freeze(&t); - return t.v[0] & 1; + int i; + crypto_uint32 mask = b; + mask = -mask; + for (i = 0; i < 32; i++) + r->v[i] ^= mask & (x->v[i] ^ r->v[i]); } -ZT_INLINE void fe25519_setone(fe25519 *r) +ZT_INLINE unsigned char fe25519_getparity(const fe25519* x) { - int i; - r->v[0] = 1; - for(i=1;i<32;i++) r->v[i]=0; + fe25519 t = *x; + fe25519_freeze(&t); + return t.v[0] & 1; } -ZT_INLINE void fe25519_setzero(fe25519 *r) +ZT_INLINE void fe25519_setone(fe25519* r) { - int i; - for(i=0;i<32;i++) r->v[i]=0; + int i; + r->v[0] = 1; + for (i = 1; i < 32; i++) + r->v[i] = 0; } -void fe25519_neg(fe25519 *r, const fe25519 *x) +ZT_INLINE void fe25519_setzero(fe25519* r) { - fe25519 t; - int i; - for(i=0;i<32;i++) t.v[i]=x->v[i]; - fe25519_setzero(r); - fe25519_sub(r, r, &t); + int i; + for (i = 0; i < 32; i++) + r->v[i] = 0; } -ZT_INLINE void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y) +void fe25519_neg(fe25519* r, const fe25519* x) { - int i; - for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i]; - reduce_add_sub(r); + fe25519 t; + int i; + for (i = 0; i < 32; i++) + t.v[i] = x->v[i]; + fe25519_setzero(r); + fe25519_sub(r, r, &t); } -void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y) +ZT_INLINE void fe25519_add(fe25519* r, const fe25519* x, const fe25519* y) { - int i; - crypto_uint32 t[32]; - t[0] = x->v[0] + 0x1da; - t[31] = x->v[31] + 0xfe; - for(i=1;i<31;i++) t[i] = x->v[i] + 0x1fe; - for(i=0;i<32;i++) r->v[i] = t[i] - y->v[i]; - reduce_add_sub(r); + int i; + for (i = 0; i < 32; i++) + r->v[i] = x->v[i] + y->v[i]; + reduce_add_sub(r); } -void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y) +void fe25519_sub(fe25519* r, const fe25519* x, const fe25519* y) { - int i,j; - crypto_uint32 t[63]; - for(i=0;i<63;i++)t[i] = 0; - - for(i=0;i<32;i++) - for(j=0;j<32;j++) - t[i+j] += x->v[i] * y->v[j]; - - for(i=32;i<63;i++) - r->v[i-32] = t[i-32] + times38(t[i]); - r->v[31] = t[31]; /* result now in r[0]...r[31] */ - - reduce_mul(r); + int i; + crypto_uint32 t[32]; + t[0] = x->v[0] + 0x1da; + t[31] = x->v[31] + 0xfe; + for (i = 1; i < 31; i++) + t[i] = x->v[i] + 0x1fe; + for (i = 0; i < 32; i++) + r->v[i] = t[i] - y->v[i]; + reduce_add_sub(r); } -ZT_INLINE void fe25519_square(fe25519 *r,const fe25519 *x) { fe25519_mul(r,x,x); } - -ZT_INLINE void fe25519_invert(fe25519 *r, const fe25519 *x) +void fe25519_mul(fe25519* r, const fe25519* x, const fe25519* y) { - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t0; - fe25519 t1; - int i; + int i, j; + crypto_uint32 t[63]; + for (i = 0; i < 63; i++) + t[i] = 0; - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t1,&z2); - /* 8 */ fe25519_square(&t0,&t1); - /* 9 */ fe25519_mul(&z9,&t0,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t0,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t0,&z9); + for (i = 0; i < 32; i++) + for (j = 0; j < 32; j++) + t[i + j] += x->v[i] * y->v[j]; - /* 2^6 - 2^1 */ fe25519_square(&t0,&z2_5_0); - /* 2^7 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^8 - 2^3 */ fe25519_square(&t0,&t1); - /* 2^9 - 2^4 */ fe25519_square(&t1,&t0); - /* 2^10 - 2^5 */ fe25519_square(&t0,&t1); - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t0,&z2_5_0); + for (i = 32; i < 63; i++) + r->v[i - 32] = t[i - 32] + times38(t[i]); + r->v[31] = t[31]; /* result now in r[0]...r[31] */ - /* 2^11 - 2^1 */ fe25519_square(&t0,&z2_10_0); - /* 2^12 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t1,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t0,&z2_20_0); - /* 2^22 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^40 - 2^0 */ fe25519_mul(&t0,&t1,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^42 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t0,&z2_50_0); - /* 2^52 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t1,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t1,&z2_100_0); - /* 2^102 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^200 - 2^0 */ fe25519_mul(&t1,&t0,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t0,&t1); - /* 2^202 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^250 - 2^0 */ fe25519_mul(&t0,&t1,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^252 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^253 - 2^3 */ fe25519_square(&t1,&t0); - /* 2^254 - 2^4 */ fe25519_square(&t0,&t1); - /* 2^255 - 2^5 */ fe25519_square(&t1,&t0); - /* 2^255 - 21 */ fe25519_mul(r,&t1,&z11); + reduce_mul(r); } -ZT_INLINE void fe25519_pow2523(fe25519 *r, const fe25519 *x) +ZT_INLINE void fe25519_square(fe25519* r, const fe25519* x) { - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t,&z2); - /* 8 */ fe25519_square(&t,&t); - /* 9 */ fe25519_mul(&z9,&t,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); - /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); - /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); - /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } - /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t,&t); - /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); - /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); - /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } - /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t,&t); - /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t,&t); - /* 2^252 - 2^2 */ fe25519_square(&t,&t); - /* 2^252 - 3 */ fe25519_mul(r,&t,x); + fe25519_mul(r, x, x); } -const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; -const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F}; - -ZT_INLINE crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ +ZT_INLINE void fe25519_invert(fe25519* r, const fe25519* x) { - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */ - x >>= 31; /* 0: no; 1: yes */ - return x; + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t0; + fe25519 t1; + int i; + + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t1, &z2); + /* 8 */ fe25519_square(&t0, &t1); + /* 9 */ fe25519_mul(&z9, &t0, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t0, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t0, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t0, &z2_5_0); + /* 2^7 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^8 - 2^3 */ fe25519_square(&t0, &t1); + /* 2^9 - 2^4 */ fe25519_square(&t1, &t0); + /* 2^10 - 2^5 */ fe25519_square(&t0, &t1); + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t0, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t0, &z2_10_0); + /* 2^12 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t1, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t0, &z2_20_0); + /* 2^22 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^40 - 2^0 */ fe25519_mul(&t0, &t1, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^42 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0, &t1); + } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0, &t0, &z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t0, &z2_50_0); + /* 2^52 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t1, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t1, &z2_100_0); + /* 2^102 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0, &t1); + } + /* 2^200 - 2^0 */ fe25519_mul(&t1, &t0, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t0, &t1); + /* 2^202 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^250 - 2^0 */ fe25519_mul(&t0, &t1, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^252 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^253 - 2^3 */ fe25519_square(&t1, &t0); + /* 2^254 - 2^4 */ fe25519_square(&t0, &t1); + /* 2^255 - 2^5 */ fe25519_square(&t1, &t0); + /* 2^255 - 21 */ fe25519_mul(r, &t1, &z11); } -void reduce_add_sub(sc25519 *r) +ZT_INLINE void fe25519_pow2523(fe25519* r, const fe25519* x) { - crypto_uint32 pb = 0; - crypto_uint32 b; - crypto_uint32 mask; - int i; - unsigned char t[32]; + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t; + int i; - for(i=0;i<32;i++) - { - pb += m[i]; - b = lt(r->v[i],pb); - t[i] = r->v[i]-pb+(b<<8); - pb = b; - } - mask = b - 1; - for(i=0;i<32;i++) - r->v[i] ^= mask & (r->v[i] ^ t[i]); + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t, &z2); + /* 8 */ fe25519_square(&t, &t); + /* 9 */ fe25519_mul(&z9, &t, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t, &z2_5_0); + /* 2^10 - 2^5 */ for (i = 1; i < 5; i++) { + fe25519_square(&t, &t); + } + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t, &z2_10_0); + /* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { + fe25519_square(&t, &t); + } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t, &z2_20_0); + /* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { + fe25519_square(&t, &t); + } + /* 2^40 - 2^0 */ fe25519_mul(&t, &t, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t, &t); + /* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { + fe25519_square(&t, &t); + } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0, &t, &z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t, &z2_50_0); + /* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { + fe25519_square(&t, &t); + } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t, &z2_100_0); + /* 2^200 - 2^100 */ for (i = 1; i < 100; i++) { + fe25519_square(&t, &t); + } + /* 2^200 - 2^0 */ fe25519_mul(&t, &t, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t, &t); + /* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { + fe25519_square(&t, &t); + } + /* 2^250 - 2^0 */ fe25519_mul(&t, &t, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t, &t); + /* 2^252 - 2^2 */ fe25519_square(&t, &t); + /* 2^252 - 3 */ fe25519_mul(r, &t, x); } -void barrett_reduce(sc25519 *r, const crypto_uint32 x[64]) +const crypto_uint32 m[32] = { 0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, + 0xA2, 0xDE, 0xF9, 0xDE, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; +const crypto_uint32 mu[33] = { 0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, + 0x08, 0x5D, 0x21, 0x06, 0x21, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F }; + +ZT_INLINE crypto_uint32 lt(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ { - /* See HAC, Alg. 14.42 */ - int i,j; - crypto_uint32 q2[66]; - crypto_uint32 *q3 = q2 + 33; - crypto_uint32 r1[33]; - crypto_uint32 r2[33]; - crypto_uint32 pb = 0; - - Utils::zero(q2); - //for (i = 0;i < 66;++i) q2[i] = 0; - Utils::zero(r2); - //for (i = 0;i < 33;++i) r2[i] = 0; - - for(i=0;i<33;i++) - for(j=0;j<33;j++) - if(i+j >= 31) q2[i+j] += mu[i]*x[j+31]; - q2[32] += (q2[31] >> 8); - q2[33] += (q2[32] >> 8); - - for(i=0;i<33;i++)r1[i] = x[i]; - for(i=0;i<32;i++) - for(j=0;j<33;j++) - if(i+j < 33) r2[i+j] += m[i]*q3[j]; - - for(i=0;i<32;i++) - { - r2[i+1] += (r2[i] >> 8); - r2[i] &= 0xff; - } - - for(i=0;i<32;i++) - { - pb += r2[i]; - crypto_uint32 b = lt(r1[i],pb); - r->v[i] = r1[i]-pb+(b<<8); - pb = b; - } - - reduce_add_sub(r); - reduce_add_sub(r); + unsigned int x = a; + x -= (unsigned int)b; /* 0..65535: no; 4294901761..4294967295: yes */ + x >>= 31; /* 0: no; 1: yes */ + return x; } -ZT_INLINE void sc25519_from32bytes(sc25519 *r,const unsigned char x[32]) +void reduce_add_sub(sc25519* r) { - int i; - crypto_uint32 t[64]; - for(i=0;i<32;i++) t[i] = x[i]; - for(i=32;i<64;++i) t[i] = 0; - barrett_reduce(r, t); + crypto_uint32 pb = 0; + crypto_uint32 b; + crypto_uint32 mask; + int i; + unsigned char t[32]; + + for (i = 0; i < 32; i++) { + pb += m[i]; + b = lt(r->v[i], pb); + t[i] = r->v[i] - pb + (b << 8); + pb = b; + } + mask = b - 1; + for (i = 0; i < 32; i++) + r->v[i] ^= mask & (r->v[i] ^ t[i]); } -ZT_INLINE void sc25519_from64bytes(sc25519 *r,const unsigned char x[64]) +void barrett_reduce(sc25519* r, const crypto_uint32 x[64]) { - int i; - crypto_uint32 t[64]; - for(i=0;i<64;i++) t[i] = x[i]; - barrett_reduce(r, t); + /* See HAC, Alg. 14.42 */ + int i, j; + crypto_uint32 q2[66]; + crypto_uint32* q3 = q2 + 33; + crypto_uint32 r1[33]; + crypto_uint32 r2[33]; + crypto_uint32 pb = 0; + + Utils::zero(q2); + // for (i = 0;i < 66;++i) q2[i] = 0; + Utils::zero(r2); + // for (i = 0;i < 33;++i) r2[i] = 0; + + for (i = 0; i < 33; i++) + for (j = 0; j < 33; j++) + if (i + j >= 31) + q2[i + j] += mu[i] * x[j + 31]; + q2[32] += (q2[31] >> 8); + q2[33] += (q2[32] >> 8); + + for (i = 0; i < 33; i++) + r1[i] = x[i]; + for (i = 0; i < 32; i++) + for (j = 0; j < 33; j++) + if (i + j < 33) + r2[i + j] += m[i] * q3[j]; + + for (i = 0; i < 32; i++) { + r2[i + 1] += (r2[i] >> 8); + r2[i] &= 0xff; + } + + for (i = 0; i < 32; i++) { + pb += r2[i]; + crypto_uint32 b = lt(r1[i], pb); + r->v[i] = r1[i] - pb + (b << 8); + pb = b; + } + + reduce_add_sub(r); + reduce_add_sub(r); } -ZT_INLINE void sc25519_to32bytes(unsigned char r[32],const sc25519 *x) +ZT_INLINE void sc25519_from32bytes(sc25519* r, const unsigned char x[32]) { - int i; - for(i=0;i<32;i++) r[i] = x->v[i]; + int i; + crypto_uint32 t[64]; + for (i = 0; i < 32; i++) + t[i] = x[i]; + for (i = 32; i < 64; ++i) + t[i] = 0; + barrett_reduce(r, t); } -ZT_INLINE void sc25519_add(sc25519 *r,const sc25519 *x,const sc25519 *y) +ZT_INLINE void sc25519_from64bytes(sc25519* r, const unsigned char x[64]) { - int i; - for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i]; - for(i=0;i<31;i++) - { - r->v[i+1] += (r->v[i] >> 8); - r->v[i] &= 0xff; - } - reduce_add_sub(r); + int i; + crypto_uint32 t[64]; + for (i = 0; i < 64; i++) + t[i] = x[i]; + barrett_reduce(r, t); } -ZT_INLINE void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y) +ZT_INLINE void sc25519_to32bytes(unsigned char r[32], const sc25519* x) { - int i,j; - crypto_uint32 t[64]; - for(i=0;i<64;i++)t[i] = 0; - - for(i=0;i<32;i++) - for(j=0;j<32;j++) - t[i+j] += x->v[i] * y->v[j]; - - for(i=0;i<63;i++) - { - t[i+1] += (t[i] >> 8); - t[i] &= 0xff; - } - - barrett_reduce(r, t); + int i; + for (i = 0; i < 32; i++) + r[i] = x->v[i]; } -ZT_INLINE void sc25519_window3(signed char r[85], const sc25519 *s) +ZT_INLINE void sc25519_add(sc25519* r, const sc25519* x, const sc25519* y) { - char carry; - int i; - for(i=0;i<10;i++) - { - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - r[8*i+5] = (s->v[3*i+1] >> 7) & 7; - r[8*i+5] ^= (s->v[3*i+2] << 1) & 7; - r[8*i+6] = (s->v[3*i+2] >> 2) & 7; - r[8*i+7] = (s->v[3*i+2] >> 5) & 7; - } - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - - /* Making it signed */ - carry = 0; - for(i=0;i<84;i++) - { - r[i] += carry; - r[i+1] += r[i] >> 3; - r[i] &= 7; - carry = r[i] >> 2; - r[i] -= carry<<3; - } - r[84] += carry; + int i; + for (i = 0; i < 32; i++) + r->v[i] = x->v[i] + y->v[i]; + for (i = 0; i < 31; i++) { + r->v[i + 1] += (r->v[i] >> 8); + r->v[i] &= 0xff; + } + reduce_add_sub(r); } -ZT_INLINE void sc25519_2interleave2(unsigned char r[127],const sc25519 *s1,const sc25519 *s2) +ZT_INLINE void sc25519_mul(sc25519* r, const sc25519* x, const sc25519* y) { - int i; - for(i=0;i<31;i++) - { - r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2); - r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); - r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); - r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); - } - r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2); - r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); - r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); + int i, j; + crypto_uint32 t[64]; + for (i = 0; i < 64; i++) + t[i] = 0; + + for (i = 0; i < 32; i++) + for (j = 0; j < 32; j++) + t[i + j] += x->v[i] * y->v[j]; + + for (i = 0; i < 63; i++) { + t[i + 1] += (t[i] >> 8); + t[i] &= 0xff; + } + + barrett_reduce(r, t); +} + +ZT_INLINE void sc25519_window3(signed char r[85], const sc25519* s) +{ + char carry; + int i; + for (i = 0; i < 10; i++) { + r[8 * i + 0] = s->v[3 * i + 0] & 7; + r[8 * i + 1] = (s->v[3 * i + 0] >> 3) & 7; + r[8 * i + 2] = (s->v[3 * i + 0] >> 6) & 7; + r[8 * i + 2] ^= (s->v[3 * i + 1] << 2) & 7; + r[8 * i + 3] = (s->v[3 * i + 1] >> 1) & 7; + r[8 * i + 4] = (s->v[3 * i + 1] >> 4) & 7; + r[8 * i + 5] = (s->v[3 * i + 1] >> 7) & 7; + r[8 * i + 5] ^= (s->v[3 * i + 2] << 1) & 7; + r[8 * i + 6] = (s->v[3 * i + 2] >> 2) & 7; + r[8 * i + 7] = (s->v[3 * i + 2] >> 5) & 7; + } + r[8 * i + 0] = s->v[3 * i + 0] & 7; + r[8 * i + 1] = (s->v[3 * i + 0] >> 3) & 7; + r[8 * i + 2] = (s->v[3 * i + 0] >> 6) & 7; + r[8 * i + 2] ^= (s->v[3 * i + 1] << 2) & 7; + r[8 * i + 3] = (s->v[3 * i + 1] >> 1) & 7; + r[8 * i + 4] = (s->v[3 * i + 1] >> 4) & 7; + + /* Making it signed */ + carry = 0; + for (i = 0; i < 84; i++) { + r[i] += carry; + r[i + 1] += r[i] >> 3; + r[i] &= 7; + carry = r[i] >> 2; + r[i] -= carry << 3; + } + r[84] += carry; +} + +ZT_INLINE void sc25519_2interleave2(unsigned char r[127], const sc25519* s1, const sc25519* s2) +{ + int i; + for (i = 0; i < 31; i++) { + r[4 * i] = (s1->v[i] & 3) ^ ((s2->v[i] & 3) << 2); + r[4 * i + 1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); + r[4 * i + 2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); + r[4 * i + 3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); + } + r[124] = (s1->v[31] & 3) ^ ((s2->v[31] & 3) << 2); + r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); + r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); } /* d */ -static const fe25519 ge25519_ecd = {{0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00, - 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52}}; +static const fe25519 ge25519_ecd = { { 0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, + 0x41, 0x4D, 0x0A, 0x70, 0x00, 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, + 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52 } }; /* 2*d */ -static const fe25519 ge25519_ec2d = {{0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00, - 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24}}; +static const fe25519 ge25519_ec2d = { { 0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, + 0x82, 0x9A, 0x14, 0xE0, 0x00, 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, + 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24 } }; /* sqrt(-1) */ -static const fe25519 ge25519_sqrtm1 = {{0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F, - 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B}}; +static const fe25519 ge25519_sqrtm1 = { { 0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, + 0xAD, 0x06, 0x18, 0x43, 0x2F, 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, + 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B } }; /* Packed coordinates of the base point */ -static const ge25519 ge25519_base = {{{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, - 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}}, - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, - 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}}}; +static const ge25519 ge25519_base = { + { { 0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, + 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21 } }, + { { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, + 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67 } } +}; /* Multiples of the base point in affine representation */ static const ge25519_aff ge25519_base_multiples_affine[425] = { -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21}} , - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}}, -{{{0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36}} , - {{0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22}}}, -{{{0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67}} , - {{0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12}}}, -{{{0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20}} , - {{0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67}} , - {{0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21}}}, -{{{0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23}} , - {{0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70}}}, -{{{0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70}} , - {{0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60}}}, -{{{0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39}} , - {{0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05}} , - {{0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d}}}, -{{{0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37}} , - {{0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28}}}, -{{{0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e}} , - {{0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77}}}, -{{{0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e}} , - {{0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e}} , - {{0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54}}}, -{{{0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b}} , - {{0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a}}}, -{{{0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60}} , - {{0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f}}}, -{{{0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c}} , - {{0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d}} , - {{0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59}}}, -{{{0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17}} , - {{0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73}}}, -{{{0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08}} , - {{0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72}}}, -{{{0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07}} , - {{0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b}} , - {{0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40}}}, -{{{0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d}} , - {{0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c}}}, -{{{0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31}} , - {{0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65}}}, -{{{0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74}} , - {{0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a}} , - {{0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16}}}, -{{{0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24}} , - {{0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37}}}, -{{{0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29}} , - {{0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15}}}, -{{{0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06}} , - {{0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48}} , - {{0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73}}}, -{{{0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b}} , - {{0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d}}}, -{{{0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28}} , - {{0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d}}}, -{{{0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45}} , - {{0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a}} , - {{0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21}}}, -{{{0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b}} , - {{0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d}}}, -{{{0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45}} , - {{0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69}}}, -{{{0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67}} , - {{0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29}} , - {{0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c}}}, -{{{0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e}} , - {{0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e}}}, -{{{0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55}} , - {{0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04}}}, -{{{0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61}} , - {{0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48}} , - {{0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31}}}, -{{{0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79}} , - {{0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e}}}, -{{{0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d}} , - {{0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72}}}, -{{{0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d}} , - {{0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b}} , - {{0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73}}}, -{{{0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33}} , - {{0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53}}}, -{{{0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56}} , - {{0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a}}}, -{{{0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44}} , - {{0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b}} , - {{0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f}}}, -{{{0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b}} , - {{0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17}}}, -{{{0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37}} , - {{0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c}}}, -{{{0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01}} , - {{0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63}} , - {{0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04}}}, -{{{0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f}} , - {{0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d}}}, -{{{0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e}} , - {{0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a}}}, -{{{0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b}} , - {{0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18}} , - {{0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e}}}, -{{{0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a}} , - {{0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67}}}, -{{{0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05}} , - {{0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78}}}, -{{{0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52}} , - {{0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50}} , - {{0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f}}}, -{{{0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d}} , - {{0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a}}}, -{{{0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a}} , - {{0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a}}}, -{{{0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56}} , - {{0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52}} , - {{0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50}}}, -{{{0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f}} , - {{0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41}}}, -{{{0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f}} , - {{0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68}}}, -{{{0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e}} , - {{0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b}} , - {{0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34}}}, -{{{0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00}} , - {{0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72}}}, -{{{0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15}} , - {{0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c}}}, -{{{0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f}} , - {{0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08}} , - {{0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27}}}, -{{{0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a}} , - {{0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77}}}, -{{{0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d}} , - {{0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c}}}, -{{{0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71}} , - {{0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30}} , - {{0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40}}}, -{{{0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42}} , - {{0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70}}}, -{{{0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e}} , - {{0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e}}}, -{{{0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c}} , - {{0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57}} , - {{0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b}}}, -{{{0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20}} , - {{0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32}}}, -{{{0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68}} , - {{0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d}}}, -{{{0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59}} , - {{0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04}} , - {{0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72}}}, -{{{0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62}} , - {{0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03}}}, -{{{0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69}} , - {{0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f}}}, -{{{0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02}} , - {{0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d}} , - {{0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54}}}, -{{{0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b}} , - {{0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19}}}, -{{{0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f}} , - {{0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64}}}, -{{{0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71}} , - {{0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22}} , - {{0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79}}}, -{{{0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c}} , - {{0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57}}}, -{{{0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e}} , - {{0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f}}}, -{{{0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f}} , - {{0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f}} , - {{0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77}}}, -{{{0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f}} , - {{0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b}}}, -{{{0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39}} , - {{0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f}}}, -{{{0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f}} , - {{0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47}} , - {{0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28}}}, -{{{0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22}} , - {{0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63}}}, -{{{0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17}} , - {{0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65}}}, -{{{0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a}} , - {{0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36}} , - {{0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b}}}, -{{{0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f}} , - {{0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16}}}, -{{{0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b}} , - {{0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07}}}, -{{{0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60}} , - {{0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08}} , - {{0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47}}}, -{{{0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b}} , - {{0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63}}}, -{{{0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d}} , - {{0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51}}}, -{{{0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b}} , - {{0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f}} , - {{0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f}}}, -{{{0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08}} , - {{0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38}}}, -{{{0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10}} , - {{0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49}}}, -{{{0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25}} , - {{0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05}} , - {{0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23}}}, -{{{0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69}} , - {{0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e}}}, -{{{0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12}} , - {{0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07}}}, -{{{0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62}} , - {{0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e}} , - {{0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a}}}, -{{{0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f}} , - {{0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13}}}, -{{{0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c}} , - {{0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f}}}, -{{{0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e}} , - {{0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c}} , - {{0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f}}}, -{{{0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c}} , - {{0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00}}}, -{{{0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77}} , - {{0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72}}}, -{{{0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a}} , - {{0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51}} , - {{0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35}}}, -{{{0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56}} , - {{0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c}}}, -{{{0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f}} , - {{0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13}}}, -{{{0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33}} , - {{0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33}} , - {{0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c}}}, -{{{0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f}} , - {{0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a}}}, -{{{0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39}} , - {{0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34}}}, -{{{0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30}} , - {{0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60}} , - {{0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b}}}, -{{{0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e}} , - {{0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d}}}, -{{{0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a}} , - {{0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08}}}, -{{{0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19}} , - {{0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28}} , - {{0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09}}}, -{{{0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34}} , - {{0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b}}}, -{{{0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57}} , - {{0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79}}}, -{{{0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c}} , - {{0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49}} , - {{0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32}}}, -{{{0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65}} , - {{0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50}}}, -{{{0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34}} , - {{0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51}}}, -{{{0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09}} , - {{0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46}} , - {{0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f}}}, -{{{0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43}} , - {{0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d}}}, -{{{0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c}} , - {{0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70}}}, -{{{0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62}} , - {{0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b}} , - {{0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09}}}, -{{{0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e}} , - {{0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10}}}, -{{{0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20}} , - {{0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03}}}, -{{{0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b}} , - {{0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19}} , - {{0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e}}}, -{{{0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45}} , - {{0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52}}}, -{{{0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06}} , - {{0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34}}}, -{{{0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39}} , - {{0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d}} , - {{0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31}}}, -{{{0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22}} , - {{0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62}}}, -{{{0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32}} , - {{0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42}}}, -{{{0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04}} , - {{0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63}} , - {{0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b}}}, -{{{0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b}} , - {{0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47}}}, -{{{0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66}} , - {{0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48}}}, -{{{0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06}} , - {{0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f}} , - {{0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66}}}, -{{{0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d}} , - {{0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b}}}, -{{{0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72}} , - {{0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02}}}, -{{{0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c}} , - {{0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78}} , - {{0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65}}}, -{{{0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21}} , - {{0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50}}}, -{{{0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d}} , - {{0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56}}}, -{{{0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77}} , - {{0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53}} , - {{0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a}}}, -{{{0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26}} , - {{0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a}}}, -{{{0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28}} , - {{0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d}}}, -{{{0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56}} , - {{0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21}} , - {{0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a}}}, -{{{0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b}} , - {{0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c}}}, -{{{0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d}} , - {{0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c}}}, -{{{0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f}} , - {{0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f}} , - {{0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59}}}, -{{{0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08}} , - {{0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b}}}, -{{{0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06}} , - {{0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22}}}, -{{{0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78}} , - {{0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17}} , - {{0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b}}}, -{{{0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01}} , - {{0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b}}}, -{{{0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06}} , - {{0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36}}}, -{{{0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f}} , - {{0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b}} , - {{0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b}}}, -{{{0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f}} , - {{0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53}}}, -{{{0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e}} , - {{0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41}}}, -{{{0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61}} , - {{0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13}} , - {{0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08}}}, -{{{0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f}} , - {{0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16}}}, -{{{0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c}} , - {{0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16}}}, -{{{0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25}} , - {{0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e}} , - {{0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e}}}, -{{{0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28}} , - {{0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32}}}, -{{{0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b}} , - {{0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e}}}, -{{{0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c}} , - {{0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27}} , - {{0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57}}}, -{{{0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c}} , - {{0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12}}}, -{{{0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22}} , - {{0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a}}}, -{{{0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c}} , - {{0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31}} , - {{0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77}}}, -{{{0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50}} , - {{0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f}}}, -{{{0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f}} , - {{0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f}}}, -{{{0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24}} , - {{0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73}} , - {{0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11}}}, -{{{0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54}} , - {{0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03}}}, -{{{0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07}} , - {{0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c}}}, -{{{0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02}} , - {{0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28}} , - {{0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54}}}, -{{{0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c}} , - {{0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42}}}, -{{{0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54}} , - {{0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b}}}, -{{{0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a}} , - {{0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38}} , - {{0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d}}}, -{{{0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68}} , - {{0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b}}}, -{{{0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b}} , - {{0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01}}}, -{{{0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37}} , - {{0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e}} , - {{0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f}}}, -{{{0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d}} , - {{0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e}}}, -{{{0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d}} , - {{0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07}}}, -{{{0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f}} , - {{0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70}} , - {{0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14}}}, -{{{0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47}} , - {{0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10}}}, -{{{0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f}} , - {{0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f}}}, -{{{0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37}} , - {{0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c}} , - {{0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c}}}, -{{{0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a}} , - {{0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49}}}, -{{{0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25}} , - {{0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67}}}, -{{{0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04}} , - {{0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60}} , - {{0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22}}}, -{{{0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48}} , - {{0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55}}}, -{{{0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13}} , - {{0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29}}}, -{{{0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37}} , - {{0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24}} , - {{0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65}}}, -{{{0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72}} , - {{0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e}}}, -{{{0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d}} , - {{0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c}}}, -{{{0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a}} , - {{0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e}} , - {{0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e}}}, -{{{0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e}} , - {{0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b}}}, -{{{0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20}} , - {{0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79}}}, -{{{0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56}} , - {{0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14}} , - {{0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44}}}, -{{{0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a}} , - {{0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73}}}, -{{{0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13}} , - {{0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c}}}, -{{{0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f}} , - {{0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b}} , - {{0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c}}}, -{{{0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a}} , - {{0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65}}}, -{{{0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53}} , - {{0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09}}}, -{{{0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f}} , - {{0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b}} , - {{0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61}}}, -{{{0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06}} , - {{0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d}}}, -{{{0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76}} , - {{0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e}}}, -{{{0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a}} , - {{0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07}} , - {{0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16}}}, -{{{0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46}} , - {{0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b}}}, -{{{0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16}} , - {{0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08}}}, -{{{0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59}} , - {{0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10}} , - {{0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13}}}, -{{{0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b}} , - {{0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c}}}, -{{{0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70}} , - {{0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65}}}, -{{{0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e}} , - {{0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e}} , - {{0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c}}}, -{{{0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c}} , - {{0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26}}}, -{{{0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72}} , - {{0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c}}}, -{{{0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59}} , - {{0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11}} , - {{0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43}}}, -{{{0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06}} , - {{0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10}}}, -{{{0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48}} , - {{0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e}}}, -{{{0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e}} , - {{0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e}} , - {{0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70}}}, -{{{0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33}} , - {{0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b}}}, -{{{0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f}} , - {{0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56}}}, -{{{0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36}} , - {{0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c}} , - {{0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74}}}, -{{{0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53}} , - {{0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c}}}, -{{{0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76}} , - {{0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20}}}, -{{{0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b}} , - {{0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e}} , - {{0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30}}}, -{{{0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49}} , - {{0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f}}}, -{{{0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46}} , - {{0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20}}}, -{{{0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07}} , - {{0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10}} , - {{0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29}}}, -{{{0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e}} , - {{0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35}}}, -{{{0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e}} , - {{0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c}}}, -{{{0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31}} , - {{0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b}} , - {{0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f}}}, -{{{0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25}} , - {{0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17}}}, -{{{0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35}} , - {{0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27}}}, -{{{0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71}} , - {{0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76}} , - {{0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24}}}, -{{{0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d}} , - {{0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45}}}, -{{{0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04}} , - {{0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45}}}, -{{{0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75}} , - {{0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d}} , - {{0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d}}}, -{{{0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16}} , - {{0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23}}}, -{{{0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45}} , - {{0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57}}}, -{{{0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66}} , - {{0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d}} , - {{0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10}}}, -{{{0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c}} , - {{0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30}}}, -{{{0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43}} , - {{0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11}}}, -{{{0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27}} , - {{0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46}} , - {{0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d}}}, -{{{0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75}} , - {{0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60}}}, -{{{0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d}} , - {{0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04}}}, -{{{0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66}} , - {{0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50}} , - {{0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50}}}, -{{{0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07}} , - {{0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a}}}, -{{{0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d}} , - {{0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b}}}, -{{{0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25}} , - {{0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24}} , - {{0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02}}}, -{{{0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05}} , - {{0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58}}}, -{{{0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67}} , - {{0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e}}}, -{{{0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d}} , - {{0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28}} , - {{0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55}}}, -{{{0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e}} , - {{0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d}}}, -{{{0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19}} , - {{0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a}}}, -{{{0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39}} , - {{0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e}} , - {{0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e}}}, -{{{0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59}} , - {{0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c}}}, -{{{0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68}} , - {{0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e}}}, -{{{0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b}} , - {{0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a}} , - {{0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40}}}, -{{{0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24}} , - {{0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b}}}, -{{{0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c}} , - {{0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a}}}, -{{{0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58}} , - {{0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19}} , - {{0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52}}}, -{{{0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08}} , - {{0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09}}}, -{{{0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e}} , - {{0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e}}}, -{{{0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03}} , - {{0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a}} , - {{0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f}}}, -{{{0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34}} , - {{0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09}}}, -{{{0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06}} , - {{0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f}}}, -{{{0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05}} , - {{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}} + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, + 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21 } }, + { { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 } } }, + { { { 0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, + 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36 } }, + { { 0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, + 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22 } } }, + { { { 0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, + 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67 } }, + { { 0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, + 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12 } } }, + { { { 0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, + 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20 } }, + { { 0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, + 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, + 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67 } }, + { { 0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, + 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21 } } }, + { { { 0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, + 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23 } }, + { { 0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, + 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70 } } }, + { { { 0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, + 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70 } }, + { { 0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, + 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60 } } }, + { { { 0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, + 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39 } }, + { { 0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, + 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, + 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05 } }, + { { 0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, + 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d } } }, + { { { 0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, + 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37 } }, + { { 0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, + 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28 } } }, + { { { 0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, + 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e } }, + { { 0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, + 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77 } } }, + { { { 0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, + 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e } }, + { { 0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, + 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, + 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e } }, + { { 0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, + 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54 } } }, + { { { 0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, + 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b } }, + { { 0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, + 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a } } }, + { { { 0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, + 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60 } }, + { { 0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, + 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f } } }, + { { { 0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, + 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c } }, + { { 0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, + 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, + 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d } }, + { { 0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, + 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59 } } }, + { { { 0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, + 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17 } }, + { { 0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, + 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73 } } }, + { { { 0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, + 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08 } }, + { { 0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, + 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72 } } }, + { { { 0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, + 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07 } }, + { { 0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, + 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, + 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b } }, + { { 0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, + 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40 } } }, + { { { 0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, + 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d } }, + { { 0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, + 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c } } }, + { { { 0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, + 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31 } }, + { { 0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, + 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65 } } }, + { { { 0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, + 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74 } }, + { { 0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, + 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, + 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a } }, + { { 0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, + 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16 } } }, + { { { 0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, + 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24 } }, + { { 0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, + 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37 } } }, + { { { 0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, + 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29 } }, + { { 0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, + 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15 } } }, + { { { 0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, + 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06 } }, + { { 0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, + 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, + 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48 } }, + { { 0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, + 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73 } } }, + { { { 0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, + 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b } }, + { { 0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, + 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d } } }, + { { { 0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, + 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28 } }, + { { 0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, + 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d } } }, + { { { 0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, + 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45 } }, + { { 0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, + 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, + 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a } }, + { { 0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, + 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21 } } }, + { { { 0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, + 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b } }, + { { 0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, + 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d } } }, + { { { 0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, + 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45 } }, + { { 0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, + 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69 } } }, + { { { 0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, + 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67 } }, + { { 0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, + 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, + 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29 } }, + { { 0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, + 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c } } }, + { { { 0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, + 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e } }, + { { 0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, + 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e } } }, + { { { 0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, + 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55 } }, + { { 0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, + 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04 } } }, + { { { 0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, + 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61 } }, + { { 0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, + 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, + 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48 } }, + { { 0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, + 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31 } } }, + { { { 0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, + 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79 } }, + { { 0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, + 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e } } }, + { { { 0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, + 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d } }, + { { 0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, + 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72 } } }, + { { { 0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, + 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d } }, + { { 0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, + 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, + 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b } }, + { { 0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, + 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73 } } }, + { { { 0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, + 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33 } }, + { { 0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, + 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53 } } }, + { { { 0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, + 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56 } }, + { { 0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, + 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a } } }, + { { { 0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, + 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44 } }, + { { 0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, + 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, + 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b } }, + { { 0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, + 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f } } }, + { { { 0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, + 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b } }, + { { 0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, + 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17 } } }, + { { { 0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, + 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37 } }, + { { 0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, + 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c } } }, + { { { 0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, + 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01 } }, + { { 0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, + 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, + 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63 } }, + { { 0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, + 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04 } } }, + { { { 0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, + 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f } }, + { { 0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, + 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d } } }, + { { { 0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, + 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e } }, + { { 0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, + 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a } } }, + { { { 0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, + 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b } }, + { { 0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, + 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, + 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18 } }, + { { 0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, + 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e } } }, + { { { 0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, + 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a } }, + { { 0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, + 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67 } } }, + { { { 0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, + 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05 } }, + { { 0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, + 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78 } } }, + { { { 0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, + 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52 } }, + { { 0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, + 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, + 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50 } }, + { { 0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, + 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f } } }, + { { { 0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, + 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d } }, + { { 0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, + 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a } } }, + { { { 0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, + 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a } }, + { { 0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, + 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a } } }, + { { { 0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, + 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56 } }, + { { 0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, + 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, + 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52 } }, + { { 0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, + 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50 } } }, + { { { 0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, + 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f } }, + { { 0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, + 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41 } } }, + { { { 0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, + 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f } }, + { { 0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, + 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68 } } }, + { { { 0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, + 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e } }, + { { 0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, + 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, + 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b } }, + { { 0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, + 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34 } } }, + { { { 0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, + 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00 } }, + { { 0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, + 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72 } } }, + { { { 0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, + 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15 } }, + { { 0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, + 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c } } }, + { { { 0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, + 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f } }, + { { 0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, + 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, + 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08 } }, + { { 0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, + 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27 } } }, + { { { 0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, + 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a } }, + { { 0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, + 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77 } } }, + { { { 0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, + 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d } }, + { { 0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, + 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c } } }, + { { { 0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, + 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71 } }, + { { 0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, + 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, + 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30 } }, + { { 0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, + 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40 } } }, + { { { 0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, + 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42 } }, + { { 0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, + 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70 } } }, + { { { 0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, + 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e } }, + { { 0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, + 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e } } }, + { { { 0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, + 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c } }, + { { 0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, + 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, + 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57 } }, + { { 0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, + 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b } } }, + { { { 0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, + 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20 } }, + { { 0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, + 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32 } } }, + { { { 0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, + 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68 } }, + { { 0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, + 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d } } }, + { { { 0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, + 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59 } }, + { { 0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, + 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, + 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04 } }, + { { 0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, + 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72 } } }, + { { { 0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, + 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62 } }, + { { 0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, + 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03 } } }, + { { { 0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, + 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69 } }, + { { 0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, + 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f } } }, + { { { 0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, + 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02 } }, + { { 0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, + 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, + 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d } }, + { { 0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, + 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54 } } }, + { { { 0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, + 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b } }, + { { 0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, + 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19 } } }, + { { { 0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, + 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f } }, + { { 0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, + 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64 } } }, + { { { 0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, + 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71 } }, + { { 0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, + 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, + 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22 } }, + { { 0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, + 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79 } } }, + { { { 0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, + 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c } }, + { { 0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, + 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57 } } }, + { { { 0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, + 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e } }, + { { 0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, + 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f } } }, + { { { 0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, + 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f } }, + { { 0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, + 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, + 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f } }, + { { 0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, + 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77 } } }, + { { { 0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, + 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f } }, + { { 0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, + 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b } } }, + { { { 0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, + 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39 } }, + { { 0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, + 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f } } }, + { { { 0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, + 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f } }, + { { 0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, + 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, + 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47 } }, + { { 0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, + 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28 } } }, + { { { 0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, + 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22 } }, + { { 0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, + 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63 } } }, + { { { 0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, + 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17 } }, + { { 0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, + 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65 } } }, + { { { 0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, + 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a } }, + { { 0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, + 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, + 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36 } }, + { { 0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, + 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b } } }, + { { { 0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, + 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f } }, + { { 0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, + 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16 } } }, + { { { 0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, + 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b } }, + { { 0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, + 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07 } } }, + { { { 0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, + 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60 } }, + { { 0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, + 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, + 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08 } }, + { { 0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, + 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47 } } }, + { { { 0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, + 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b } }, + { { 0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, + 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63 } } }, + { { { 0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, + 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d } }, + { { 0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, + 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51 } } }, + { { { 0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, + 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b } }, + { { 0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, + 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, + 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f } }, + { { 0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, + 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f } } }, + { { { 0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, + 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08 } }, + { { 0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, + 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38 } } }, + { { { 0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, + 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10 } }, + { { 0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, + 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49 } } }, + { { { 0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, + 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25 } }, + { { 0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, + 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, + 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05 } }, + { { 0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, + 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23 } } }, + { { { 0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, + 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69 } }, + { { 0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, + 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e } } }, + { { { 0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, + 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12 } }, + { { 0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, + 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07 } } }, + { { { 0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, + 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62 } }, + { { 0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, + 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, + 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e } }, + { { 0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, + 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a } } }, + { { { 0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, + 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f } }, + { { 0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, + 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13 } } }, + { { { 0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, + 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c } }, + { { 0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, + 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f } } }, + { { { 0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, + 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e } }, + { { 0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, + 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, + 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c } }, + { { 0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, + 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f } } }, + { { { 0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, + 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c } }, + { { 0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, + 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00 } } }, + { { { 0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, + 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77 } }, + { { 0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, + 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72 } } }, + { { { 0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, + 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a } }, + { { 0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, + 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, + 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51 } }, + { { 0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, + 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35 } } }, + { { { 0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, + 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56 } }, + { { 0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, + 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c } } }, + { { { 0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, + 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f } }, + { { 0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, + 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13 } } }, + { { { 0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, + 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33 } }, + { { 0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, + 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, + 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33 } }, + { { 0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, + 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c } } }, + { { { 0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, + 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f } }, + { { 0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, + 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a } } }, + { { { 0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, + 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39 } }, + { { 0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, + 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34 } } }, + { { { 0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, + 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30 } }, + { { 0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, + 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, + 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60 } }, + { { 0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, + 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b } } }, + { { { 0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, + 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e } }, + { { 0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, + 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d } } }, + { { { 0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, + 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a } }, + { { 0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, + 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08 } } }, + { { { 0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, + 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19 } }, + { { 0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, + 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, + 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28 } }, + { { 0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, + 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09 } } }, + { { { 0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, + 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34 } }, + { { 0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, + 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b } } }, + { { { 0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, + 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57 } }, + { { 0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, + 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79 } } }, + { { { 0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, + 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c } }, + { { 0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, + 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, + 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49 } }, + { { 0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, + 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32 } } }, + { { { 0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, + 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65 } }, + { { 0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, + 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50 } } }, + { { { 0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, + 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34 } }, + { { 0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, + 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51 } } }, + { { { 0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, + 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09 } }, + { { 0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, + 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, + 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46 } }, + { { 0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, + 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f } } }, + { { { 0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, + 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43 } }, + { { 0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, + 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d } } }, + { { { 0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, + 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c } }, + { { 0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, + 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70 } } }, + { { { 0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, + 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62 } }, + { { 0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, + 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, + 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b } }, + { { 0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, + 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09 } } }, + { { { 0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, + 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e } }, + { { 0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, + 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10 } } }, + { { { 0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, + 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20 } }, + { { 0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, + 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03 } } }, + { { { 0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, + 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b } }, + { { 0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, + 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, + 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19 } }, + { { 0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, + 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e } } }, + { { { 0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, + 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45 } }, + { { 0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, + 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52 } } }, + { { { 0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, + 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06 } }, + { { 0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, + 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34 } } }, + { { { 0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, + 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39 } }, + { { 0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, + 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, + 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d } }, + { { 0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, + 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31 } } }, + { { { 0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, + 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22 } }, + { { 0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, + 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62 } } }, + { { { 0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, + 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32 } }, + { { 0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, + 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42 } } }, + { { { 0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, + 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04 } }, + { { 0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, + 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, + 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63 } }, + { { 0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, + 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b } } }, + { { { 0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, + 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b } }, + { { 0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, + 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47 } } }, + { { { 0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, + 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66 } }, + { { 0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, + 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48 } } }, + { { { 0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, + 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06 } }, + { { 0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, + 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, + 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f } }, + { { 0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, + 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66 } } }, + { { { 0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, + 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d } }, + { { 0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, + 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b } } }, + { { { 0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, + 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72 } }, + { { 0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, + 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02 } } }, + { { { 0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, + 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c } }, + { { 0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, + 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, + 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78 } }, + { { 0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, + 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65 } } }, + { { { 0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, + 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21 } }, + { { 0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, + 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50 } } }, + { { { 0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, + 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d } }, + { { 0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, + 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56 } } }, + { { { 0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, + 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77 } }, + { { 0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, + 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, + 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53 } }, + { { 0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, + 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a } } }, + { { { 0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, + 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26 } }, + { { 0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, + 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a } } }, + { { { 0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, + 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28 } }, + { { 0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, + 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d } } }, + { { { 0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, + 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56 } }, + { { 0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, + 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, + 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21 } }, + { { 0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, + 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a } } }, + { { { 0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, + 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b } }, + { { 0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, + 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c } } }, + { { { 0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, + 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d } }, + { { 0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, + 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c } } }, + { { { 0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, + 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f } }, + { { 0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, + 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, + 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f } }, + { { 0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, + 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59 } } }, + { { { 0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, + 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08 } }, + { { 0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, + 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b } } }, + { { { 0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, + 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06 } }, + { { 0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, + 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22 } } }, + { { { 0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, + 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78 } }, + { { 0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, + 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, + 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17 } }, + { { 0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, + 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b } } }, + { { { 0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, + 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01 } }, + { { 0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, + 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b } } }, + { { { 0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, + 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06 } }, + { { 0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, + 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36 } } }, + { { { 0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, + 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f } }, + { { 0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, + 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, + 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b } }, + { { 0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, + 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b } } }, + { { { 0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, + 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f } }, + { { 0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, + 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53 } } }, + { { { 0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, + 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e } }, + { { 0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, + 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41 } } }, + { { { 0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, + 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61 } }, + { { 0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, + 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, + 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13 } }, + { { 0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, + 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08 } } }, + { { { 0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, + 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f } }, + { { 0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, + 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16 } } }, + { { { 0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, + 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c } }, + { { 0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, + 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16 } } }, + { { { 0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, + 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25 } }, + { { 0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, + 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, + 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e } }, + { { 0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, + 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e } } }, + { { { 0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, + 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28 } }, + { { 0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, + 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32 } } }, + { { { 0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, + 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b } }, + { { 0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, + 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e } } }, + { { { 0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, + 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c } }, + { { 0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, + 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, + 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27 } }, + { { 0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, + 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57 } } }, + { { { 0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, + 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c } }, + { { 0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, + 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12 } } }, + { { { 0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, + 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22 } }, + { { 0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, + 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a } } }, + { { { 0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, + 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c } }, + { { 0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, + 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, + 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31 } }, + { { 0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, + 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77 } } }, + { { { 0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, + 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50 } }, + { { 0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, + 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f } } }, + { { { 0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, + 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f } }, + { { 0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, + 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f } } }, + { { { 0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, + 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24 } }, + { { 0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, + 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, + 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73 } }, + { { 0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, + 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11 } } }, + { { { 0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, + 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54 } }, + { { 0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, + 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03 } } }, + { { { 0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, + 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07 } }, + { { 0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, + 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c } } }, + { { { 0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, + 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02 } }, + { { 0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, + 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, + 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28 } }, + { { 0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, + 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54 } } }, + { { { 0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, + 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c } }, + { { 0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, + 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42 } } }, + { { { 0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, + 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54 } }, + { { 0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, + 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b } } }, + { { { 0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, + 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a } }, + { { 0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, + 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, + 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38 } }, + { { 0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, + 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d } } }, + { { { 0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, + 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68 } }, + { { 0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, + 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b } } }, + { { { 0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, + 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b } }, + { { 0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, + 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01 } } }, + { { { 0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, + 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37 } }, + { { 0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, + 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, + 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e } }, + { { 0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, + 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f } } }, + { { { 0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, + 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d } }, + { { 0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, + 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e } } }, + { { { 0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, + 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d } }, + { { 0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, + 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07 } } }, + { { { 0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, + 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f } }, + { { 0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, + 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, + 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70 } }, + { { 0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, + 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14 } } }, + { { { 0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, + 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47 } }, + { { 0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, + 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10 } } }, + { { { 0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, + 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f } }, + { { 0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, + 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f } } }, + { { { 0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, + 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37 } }, + { { 0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, + 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, + 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c } }, + { { 0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, + 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c } } }, + { { { 0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, + 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a } }, + { { 0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, + 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49 } } }, + { { { 0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, + 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25 } }, + { { 0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, + 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67 } } }, + { { { 0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, + 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04 } }, + { { 0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, + 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, + 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60 } }, + { { 0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, + 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22 } } }, + { { { 0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, + 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48 } }, + { { 0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, + 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55 } } }, + { { { 0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, + 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13 } }, + { { 0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, + 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29 } } }, + { { { 0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, + 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37 } }, + { { 0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, + 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, + 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24 } }, + { { 0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, + 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65 } } }, + { { { 0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, + 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72 } }, + { { 0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, + 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e } } }, + { { { 0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, + 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d } }, + { { 0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, + 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c } } }, + { { { 0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, + 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a } }, + { { 0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, + 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, + 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e } }, + { { 0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, + 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e } } }, + { { { 0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, + 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e } }, + { { 0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, + 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b } } }, + { { { 0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, + 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20 } }, + { { 0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, + 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79 } } }, + { { { 0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, + 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56 } }, + { { 0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, + 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, + 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14 } }, + { { 0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, + 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44 } } }, + { { { 0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, + 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a } }, + { { 0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, + 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73 } } }, + { { { 0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, + 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13 } }, + { { 0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, + 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c } } }, + { { { 0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, + 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f } }, + { { 0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, + 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, + 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b } }, + { { 0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, + 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c } } }, + { { { 0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, + 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a } }, + { { 0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, + 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65 } } }, + { { { 0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, + 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53 } }, + { { 0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, + 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09 } } }, + { { { 0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, + 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f } }, + { { 0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, + 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, + 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b } }, + { { 0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, + 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61 } } }, + { { { 0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, + 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06 } }, + { { 0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, + 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d } } }, + { { { 0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, + 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76 } }, + { { 0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, + 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e } } }, + { { { 0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, + 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a } }, + { { 0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, + 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, + 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07 } }, + { { 0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, + 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16 } } }, + { { { 0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, + 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46 } }, + { { 0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, + 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b } } }, + { { { 0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, + 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16 } }, + { { 0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, + 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08 } } }, + { { { 0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, + 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59 } }, + { { 0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, + 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, + 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10 } }, + { { 0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, + 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13 } } }, + { { { 0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, + 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b } }, + { { 0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, + 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c } } }, + { { { 0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, + 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70 } }, + { { 0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, + 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65 } } }, + { { { 0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, + 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e } }, + { { 0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, + 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, + 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e } }, + { { 0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, + 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c } } }, + { { { 0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, + 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c } }, + { { 0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, + 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26 } } }, + { { { 0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, + 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72 } }, + { { 0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, + 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c } } }, + { { { 0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, + 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59 } }, + { { 0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, + 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, + 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11 } }, + { { 0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, + 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43 } } }, + { { { 0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, + 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06 } }, + { { 0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, + 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10 } } }, + { { { 0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, + 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48 } }, + { { 0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, + 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e } } }, + { { { 0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, + 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e } }, + { { 0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, + 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, + 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e } }, + { { 0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, + 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70 } } }, + { { { 0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, + 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33 } }, + { { 0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, + 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b } } }, + { { { 0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, + 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f } }, + { { 0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, + 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56 } } }, + { { { 0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, + 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36 } }, + { { 0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, + 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, + 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c } }, + { { 0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, + 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74 } } }, + { { { 0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, + 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53 } }, + { { 0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, + 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c } } }, + { { { 0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, + 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76 } }, + { { 0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, + 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20 } } }, + { { { 0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, + 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b } }, + { { 0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, + 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, + 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e } }, + { { 0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, + 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30 } } }, + { { { 0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, + 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49 } }, + { { 0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, + 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f } } }, + { { { 0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, + 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46 } }, + { { 0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, + 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20 } } }, + { { { 0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, + 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07 } }, + { { 0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, + 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, + 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10 } }, + { { 0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, + 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29 } } }, + { { { 0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, + 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e } }, + { { 0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, + 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35 } } }, + { { { 0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, + 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e } }, + { { 0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, + 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c } } }, + { { { 0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, + 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31 } }, + { { 0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, + 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, + 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b } }, + { { 0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, + 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f } } }, + { { { 0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, + 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25 } }, + { { 0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, + 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17 } } }, + { { { 0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, + 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35 } }, + { { 0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, + 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27 } } }, + { { { 0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, + 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71 } }, + { { 0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, + 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, + 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76 } }, + { { 0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, + 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24 } } }, + { { { 0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, + 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d } }, + { { 0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, + 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45 } } }, + { { { 0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, + 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04 } }, + { { 0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, + 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45 } } }, + { { { 0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, + 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75 } }, + { { 0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, + 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, + 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d } }, + { { 0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, + 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d } } }, + { { { 0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, + 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16 } }, + { { 0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, + 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23 } } }, + { { { 0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, + 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45 } }, + { { 0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, + 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57 } } }, + { { { 0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, + 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66 } }, + { { 0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, + 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, + 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d } }, + { { 0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, + 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10 } } }, + { { { 0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, + 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c } }, + { { 0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, + 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30 } } }, + { { { 0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, + 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43 } }, + { { 0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, + 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11 } } }, + { { { 0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, + 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27 } }, + { { 0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, + 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, + 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46 } }, + { { 0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, + 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d } } }, + { { { 0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, + 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75 } }, + { { 0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, + 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60 } } }, + { { { 0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, + 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d } }, + { { 0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, + 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04 } } }, + { { { 0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, + 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66 } }, + { { 0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, + 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, + 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50 } }, + { { 0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, + 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50 } } }, + { { { 0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, + 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07 } }, + { { 0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, + 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a } } }, + { { { 0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, + 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d } }, + { { 0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, + 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b } } }, + { { { 0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, + 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25 } }, + { { 0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, + 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, + 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24 } }, + { { 0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, + 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02 } } }, + { { { 0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, + 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05 } }, + { { 0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, + 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58 } } }, + { { { 0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, + 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67 } }, + { { 0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, + 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e } } }, + { { { 0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, + 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d } }, + { { 0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, + 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, + 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28 } }, + { { 0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, + 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55 } } }, + { { { 0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, + 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e } }, + { { 0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, + 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d } } }, + { { { 0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, + 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19 } }, + { { 0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, + 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a } } }, + { { { 0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, + 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39 } }, + { { 0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, + 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, + 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e } }, + { { 0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, + 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e } } }, + { { { 0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, + 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59 } }, + { { 0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, + 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c } } }, + { { { 0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, + 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68 } }, + { { 0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, + 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e } } }, + { { { 0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, + 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b } }, + { { 0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, + 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, + 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a } }, + { { 0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, + 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40 } } }, + { { { 0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, + 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24 } }, + { { 0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, + 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b } } }, + { { { 0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, + 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c } }, + { { 0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, + 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a } } }, + { { { 0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, + 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58 } }, + { { 0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, + 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, + 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19 } }, + { { 0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, + 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52 } } }, + { { { 0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, + 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08 } }, + { { 0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, + 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09 } } }, + { { { 0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, + 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e } }, + { { 0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, + 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e } } }, + { { { 0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, + 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03 } }, + { { 0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, + 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, + 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a } }, + { { 0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, + 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f } } }, + { { { 0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, + 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34 } }, + { { 0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, + 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09 } } }, + { { { 0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, + 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06 } }, + { { 0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, + 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f } } }, + { { { 0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, + 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05 } }, + { { 0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, + 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51 } } } }; -ZT_INLINE void p1p1_to_p2(ge25519_p2 *r,const ge25519_p1p1 *p) +ZT_INLINE void p1p1_to_p2(ge25519_p2* r, const ge25519_p1p1* p) { - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); + fe25519_mul(&r->x, &p->x, &p->t); + fe25519_mul(&r->y, &p->y, &p->z); + fe25519_mul(&r->z, &p->z, &p->t); } -ZT_INLINE void p1p1_to_p2_2(ge25519_p3 *r,const ge25519_p1p1 *p) +ZT_INLINE void p1p1_to_p2_2(ge25519_p3* r, const ge25519_p1p1* p) { - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); + fe25519_mul(&r->x, &p->x, &p->t); + fe25519_mul(&r->y, &p->y, &p->z); + fe25519_mul(&r->z, &p->z, &p->t); } -ZT_INLINE void p1p1_to_p3(ge25519_p3 *r,const ge25519_p1p1 *p) +ZT_INLINE void p1p1_to_p3(ge25519_p3* r, const ge25519_p1p1* p) { - p1p1_to_p2_2(r, p); - fe25519_mul(&r->t, &p->x, &p->y); + p1p1_to_p2_2(r, p); + fe25519_mul(&r->t, &p->x, &p->y); } -ZT_INLINE void ge25519_mixadd2(ge25519_p3 *r,const ge25519_aff *q) +ZT_INLINE void ge25519_mixadd2(ge25519_p3* r, const ge25519_aff* q) { - fe25519 a,b,t1,t2,c,d,e,f,g,h,qt; - fe25519_mul(&qt, &q->x, &q->y); - fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_sub(&t1, &q->y, &q->x); - fe25519_add(&t2, &q->y, &q->x); - fe25519_mul(&a, &a, &t1); - fe25519_mul(&b, &b, &t2); - fe25519_sub(&e, &b, &a); /* E = B-A */ - fe25519_add(&h, &b, &a); /* H = B+A */ - fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ - fe25519_sub(&f, &d, &c); /* F = D-C */ - fe25519_add(&g, &d, &c); /* G = D+C */ - fe25519_mul(&r->x, &e, &f); - fe25519_mul(&r->y, &h, &g); - fe25519_mul(&r->z, &g, &f); - fe25519_mul(&r->t, &e, &h); + fe25519 a, b, t1, t2, c, d, e, f, g, h, qt; + fe25519_mul(&qt, &q->x, &q->y); + fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_sub(&t1, &q->y, &q->x); + fe25519_add(&t2, &q->y, &q->x); + fe25519_mul(&a, &a, &t1); + fe25519_mul(&b, &b, &t2); + fe25519_sub(&e, &b, &a); /* E = B-A */ + fe25519_add(&h, &b, &a); /* H = B+A */ + fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ + fe25519_sub(&f, &d, &c); /* F = D-C */ + fe25519_add(&g, &d, &c); /* G = D+C */ + fe25519_mul(&r->x, &e, &f); + fe25519_mul(&r->y, &h, &g); + fe25519_mul(&r->z, &g, &f); + fe25519_mul(&r->t, &e, &h); } -ZT_INLINE void add_p1p1(ge25519_p1p1 *r,const ge25519_p3 *p,const ge25519_p3 *q) +ZT_INLINE void add_p1p1(ge25519_p1p1* r, const ge25519_p3* p, const ge25519_p3* q) { - fe25519 a, b, c, d, t; + fe25519 a, b, c, d, t; - fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_sub(&t, &q->y, &q->x); - fe25519_mul(&a, &a, &t); - fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_add(&t, &q->x, &q->y); - fe25519_mul(&b, &b, &t); - fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ - fe25519_add(&d, &d, &d); - fe25519_sub(&r->x, &b, &a); /* E = B-A */ - fe25519_sub(&r->t, &d, &c); /* F = D-C */ - fe25519_add(&r->z, &d, &c); /* G = D+C */ - fe25519_add(&r->y, &b, &a); /* H = B+A */ + fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_sub(&t, &q->y, &q->x); + fe25519_mul(&a, &a, &t); + fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_add(&t, &q->x, &q->y); + fe25519_mul(&b, &b, &t); + fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ + fe25519_add(&d, &d, &d); + fe25519_sub(&r->x, &b, &a); /* E = B-A */ + fe25519_sub(&r->t, &d, &c); /* F = D-C */ + fe25519_add(&r->z, &d, &c); /* G = D+C */ + fe25519_add(&r->y, &b, &a); /* H = B+A */ } /* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */ -ZT_INLINE void dbl_p1p1(ge25519_p1p1 *r,const ge25519_p2 *p) +ZT_INLINE void dbl_p1p1(ge25519_p1p1* r, const ge25519_p2* p) { - fe25519 a,b,c,d; - fe25519_square(&a, &p->x); - fe25519_square(&b, &p->y); - fe25519_square(&c, &p->z); - fe25519_add(&c, &c, &c); - fe25519_neg(&d, &a); + fe25519 a, b, c, d; + fe25519_square(&a, &p->x); + fe25519_square(&b, &p->y); + fe25519_square(&c, &p->z); + fe25519_add(&c, &c, &c); + fe25519_neg(&d, &a); - fe25519_add(&r->x, &p->x, &p->y); - fe25519_square(&r->x, &r->x); - fe25519_sub(&r->x, &r->x, &a); - fe25519_sub(&r->x, &r->x, &b); - fe25519_add(&r->z, &d, &b); - fe25519_sub(&r->t, &r->z, &c); - fe25519_sub(&r->y, &d, &b); + fe25519_add(&r->x, &p->x, &p->y); + fe25519_square(&r->x, &r->x); + fe25519_sub(&r->x, &r->x, &a); + fe25519_sub(&r->x, &r->x, &b); + fe25519_add(&r->z, &d, &b); + fe25519_sub(&r->t, &r->z, &c); + fe25519_sub(&r->y, &d, &b); } /* Constant-time version of: if(b) r = p */ -ZT_INLINE void cmov_aff(ge25519_aff *r,const ge25519_aff *p,unsigned char b) +ZT_INLINE void cmov_aff(ge25519_aff* r, const ge25519_aff* p, unsigned char b) { - fe25519_cmov(&r->x, &p->x, b); - fe25519_cmov(&r->y, &p->y, b); + fe25519_cmov(&r->x, &p->x, b); + fe25519_cmov(&r->y, &p->y, b); } -ZT_INLINE unsigned char equal(signed char b,signed char c) +ZT_INLINE unsigned char equal(signed char b, signed char c) { - unsigned char ub = b; - unsigned char uc = c; - unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ - crypto_uint32 y = x; /* 0: yes; 1..255: no */ - y -= 1; /* 4294967295: yes; 0..254: no */ - y >>= 31; /* 1: yes; 0: no */ - return (unsigned char)y; + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + crypto_uint32 y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return (unsigned char)y; } ZT_INLINE unsigned char negative(signed char b) { - unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ - x >>= 63; /* 1: yes; 0: no */ - return (unsigned char)x; + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (unsigned char)x; } -ZT_INLINE void choose_t(ge25519_aff *t,unsigned long long pos,signed char b) +ZT_INLINE void choose_t(ge25519_aff* t, unsigned long long pos, signed char b) { - /* constant time */ - fe25519 v; - *t = ge25519_base_multiples_affine[5*pos+0]; - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+1],equal(b,1) | equal(b,-1)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+2],equal(b,2) | equal(b,-2)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+3],equal(b,3) | equal(b,-3)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+4],equal(b,-4)); - fe25519_neg(&v, &t->x); - fe25519_cmov(&t->x, &v, negative(b)); + /* constant time */ + fe25519 v; + *t = ge25519_base_multiples_affine[5 * pos + 0]; + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 1], equal(b, 1) | equal(b, -1)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 2], equal(b, 2) | equal(b, -2)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 3], equal(b, 3) | equal(b, -3)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 4], equal(b, -4)); + fe25519_neg(&v, &t->x); + fe25519_cmov(&t->x, &v, negative(b)); } -ZT_INLINE void setneutral(ge25519 *r) +ZT_INLINE void setneutral(ge25519* r) { - fe25519_setzero(&r->x); - fe25519_setone(&r->y); - fe25519_setone(&r->z); - fe25519_setzero(&r->t); + fe25519_setzero(&r->x); + fe25519_setone(&r->y); + fe25519_setone(&r->z); + fe25519_setzero(&r->t); } /* return 0 on success, -1 otherwise */ -ZT_INLINE int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) +ZT_INLINE int ge25519_unpackneg_vartime(ge25519_p3* r, const unsigned char p[32]) { - unsigned char par; - fe25519 t, chk, num, den, den2, den4, den6; - fe25519_setone(&r->z); - par = p[31] >> 7; - fe25519_unpack(&r->y, p); - fe25519_square(&num, &r->y); /* x = y^2 */ - fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ - fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ - fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ + unsigned char par; + fe25519 t, chk, num, den, den2, den4, den6; + fe25519_setone(&r->z); + par = p[31] >> 7; + fe25519_unpack(&r->y, p); + fe25519_square(&num, &r->y); /* x = y^2 */ + fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ + fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ + fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - fe25519_square(&den2, &den); - fe25519_square(&den4, &den2); - fe25519_mul(&den6, &den4, &den2); - fe25519_mul(&t, &den6, &num); - fe25519_mul(&t, &t, &den); + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + fe25519_square(&den2, &den); + fe25519_square(&den4, &den2); + fe25519_mul(&den6, &den4, &den2); + fe25519_mul(&t, &den6, &num); + fe25519_mul(&t, &t, &den); - fe25519_pow2523(&t, &t); - /* 2. computation of r->x = t * num * den^3 */ - fe25519_mul(&t, &t, &num); - fe25519_mul(&t, &t, &den); - fe25519_mul(&t, &t, &den); - fe25519_mul(&r->x, &t, &den); + fe25519_pow2523(&t, &t); + /* 2. computation of r->x = t * num * den^3 */ + fe25519_mul(&t, &t, &num); + fe25519_mul(&t, &t, &den); + fe25519_mul(&t, &t, &den); + fe25519_mul(&r->x, &t, &den); - /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); + /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (! fe25519_iseq_vartime(&chk, &num)) + fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); - /* 4. Now we have one of the two square roots, except if input was not a square */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - return -1; + /* 4. Now we have one of the two square roots, except if input was not a square */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (! fe25519_iseq_vartime(&chk, &num)) + return -1; - /* 5. Choose the desired square root according to parity: */ - if(fe25519_getparity(&r->x) != (1-par)) - fe25519_neg(&r->x, &r->x); + /* 5. Choose the desired square root according to parity: */ + if (fe25519_getparity(&r->x) != (1 - par)) + fe25519_neg(&r->x, &r->x); - fe25519_mul(&r->t, &r->x, &r->y); - return 0; + fe25519_mul(&r->t, &r->x, &r->y); + return 0; } -void ge25519_pack(unsigned char r[32],const ge25519_p3 *p) +void ge25519_pack(unsigned char r[32], const ge25519_p3* p) { - fe25519 tx, ty, zi; - fe25519_invert(&zi, &p->z); - fe25519_mul(&tx, &p->x, &zi); - fe25519_mul(&ty, &p->y, &zi); - fe25519_pack(r, &ty); - r[31] ^= fe25519_getparity(&tx) << 7; + fe25519 tx, ty, zi; + fe25519_invert(&zi, &p->z); + fe25519_mul(&tx, &p->x, &zi); + fe25519_mul(&ty, &p->y, &zi); + fe25519_pack(r, &ty); + r[31] ^= fe25519_getparity(&tx) << 7; } /* computes [s1]p1 + [s2]p2 */ -ZT_INLINE void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2) +ZT_INLINE void ge25519_double_scalarmult_vartime( + ge25519_p3* r, + const ge25519_p3* p1, + const sc25519* s1, + const ge25519_p3* p2, + const sc25519* s2) { - ge25519_p1p1 tp1p1; - ge25519_p3 pre[16]; - char *pre5 = (char *)(&(pre[5])); // eliminate type punning warning - unsigned char b[127]; - int i; + ge25519_p1p1 tp1p1; + ge25519_p3 pre[16]; + char* pre5 = (char*)(&(pre[5])); // eliminate type punning warning + unsigned char b[127]; + int i; - /* precomputation s2 s1 */ - setneutral(pre); /* 00 00 */ - pre[1] = *p1; /* 00 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */ - add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */ - pre[4] = *p2; /* 01 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */ - add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)pre5); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ - add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ - add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ - add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ - add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ + /* precomputation s2 s1 */ + setneutral(pre); /* 00 00 */ + pre[1] = *p1; /* 00 01 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)p1); + p1p1_to_p3(&pre[2], &tp1p1); /* 00 10 */ + add_p1p1(&tp1p1, &pre[1], &pre[2]); + p1p1_to_p3(&pre[3], &tp1p1); /* 00 11 */ + pre[4] = *p2; /* 01 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[4]); + p1p1_to_p3(&pre[5], &tp1p1); /* 01 01 */ + add_p1p1(&tp1p1, &pre[2], &pre[4]); + p1p1_to_p3(&pre[6], &tp1p1); /* 01 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[4]); + p1p1_to_p3(&pre[7], &tp1p1); /* 01 11 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)p2); + p1p1_to_p3(&pre[8], &tp1p1); /* 10 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[8]); + p1p1_to_p3(&pre[9], &tp1p1); /* 10 01 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)pre5); + p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[8]); + p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ + add_p1p1(&tp1p1, &pre[4], &pre[8]); + p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[12]); + p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ + add_p1p1(&tp1p1, &pre[2], &pre[12]); + p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[12]); + p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ - sc25519_2interleave2(b,s1,s2); + sc25519_2interleave2(b, s1, s2); - /* scalar multiplication */ - *r = pre[b[126]]; - for(i=125;i>=0;i--) - { - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - p1p1_to_p2((ge25519_p2 *) r, &tp1p1); - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - if(b[i]!=0) - { - p1p1_to_p3(r, &tp1p1); - add_p1p1(&tp1p1, r, &pre[b[i]]); - } - if(i != 0) p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - else p1p1_to_p3(r, &tp1p1); - } + /* scalar multiplication */ + *r = pre[b[126]]; + for (i = 125; i >= 0; i--) { + dbl_p1p1(&tp1p1, (ge25519_p2*)r); + p1p1_to_p2((ge25519_p2*)r, &tp1p1); + dbl_p1p1(&tp1p1, (ge25519_p2*)r); + if (b[i] != 0) { + p1p1_to_p3(r, &tp1p1); + add_p1p1(&tp1p1, r, &pre[b[i]]); + } + if (i != 0) + p1p1_to_p2((ge25519_p2*)r, &tp1p1); + else + p1p1_to_p3(r, &tp1p1); + } } -void ge25519_scalarmult_base(ge25519_p3 *r,const sc25519 *s) +void ge25519_scalarmult_base(ge25519_p3* r, const sc25519* s) { - signed char b[85]; - int i; - ge25519_aff t; - sc25519_window3(b,s); + signed char b[85]; + int i; + ge25519_aff t; + sc25519_window3(b, s); - choose_t((ge25519_aff *)r, 0, b[0]); - fe25519_setone(&r->z); - fe25519_mul(&r->t, &r->x, &r->y); - for(i=1;i<85;i++) - { - choose_t(&t, (unsigned long long) i, b[i]); - ge25519_mixadd2(r, &t); - } + choose_t((ge25519_aff*)r, 0, b[0]); + fe25519_setone(&r->z); + fe25519_mul(&r->t, &r->x, &r->y); + for (i = 1; i < 85; i++) { + choose_t(&t, (unsigned long long)i, b[i]); + ge25519_mixadd2(r, &t); + } } -ZT_INLINE void get_hram(unsigned char *hram,const unsigned char *sm,const unsigned char *pk,unsigned char *playground,unsigned long long smlen) +ZT_INLINE void get_hram( + unsigned char* hram, + const unsigned char* sm, + const unsigned char* pk, + unsigned char* playground, + unsigned long long smlen) { - unsigned long long i; + unsigned long long i; - for (i = 0;i < 32;++i) playground[i] = sm[i]; - for (i = 32;i < 64;++i) playground[i] = pk[i-32]; - for (i = 64;i < smlen;++i) playground[i] = sm[i]; + for (i = 0; i < 32; ++i) + playground[i] = sm[i]; + for (i = 32; i < 64; ++i) + playground[i] = pk[i - 32]; + for (i = 64; i < smlen; ++i) + playground[i] = sm[i]; - ZeroTier::SHA512(hram,playground,(unsigned int)smlen); + ZeroTier::SHA512(hram, playground, (unsigned int)smlen); } // -------------------------------------------------------------------------------------------------------------------- -} // anonymous namespace +} // anonymous namespace namespace ZeroTier { -void C25519::generateCombined(uint8_t *pub,uint8_t *priv) +void C25519::generateCombined(uint8_t* pub, uint8_t* priv) { - Utils::getSecureRandom(priv,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); - s_calcPubDH(pub, priv); - s_calcPubED(pub, priv); + Utils::getSecureRandom(priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + s_calcPubDH(pub, priv); + s_calcPubED(pub, priv); } -void C25519::generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]) +void C25519::generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE], uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]) { - Utils::getSecureRandom(priv,ZT_C25519_ECDH_PRIVATE_KEY_SIZE); - s_calcPubDH(pub, priv); + Utils::getSecureRandom(priv, ZT_C25519_ECDH_PRIVATE_KEY_SIZE); + s_calcPubDH(pub, priv); } -void C25519::agree(const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE],const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]) +void C25519::agree( + const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE], + const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE], + uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]) { - crypto_scalarmult(rawkey,mine,their); + crypto_scalarmult(rawkey, mine, their); } -void C25519::sign(const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,void *signature) +void C25519::sign( + const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE], + const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + const void* msg, + unsigned int len, + void* signature) { - unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) - SHA512(digest,msg,len); + unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) + SHA512(digest, msg, len); - sc25519 sck, scs, scsk; - ge25519 ger; - unsigned char r[32]; - unsigned char s[32]; - unsigned char extsk[64]; - unsigned char hmg[crypto_hash_sha512_BYTES]; - unsigned char hram[crypto_hash_sha512_BYTES]; - unsigned char *sig = (unsigned char *)signature; + sc25519 sck, scs, scsk; + ge25519 ger; + unsigned char r[32]; + unsigned char s[32]; + unsigned char extsk[64]; + unsigned char hmg[crypto_hash_sha512_BYTES]; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned char* sig = (unsigned char*)signature; - SHA512(extsk,myPrivate + 32,32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; + SHA512(extsk, myPrivate + 32, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; - for(unsigned int i=0;i<32;i++) - sig[32 + i] = extsk[32 + i]; - for(unsigned int i=0;i<32;i++) - sig[64 + i] = digest[i]; + for (unsigned int i = 0; i < 32; i++) + sig[32 + i] = extsk[32 + i]; + for (unsigned int i = 0; i < 32; i++) + sig[64 + i] = digest[i]; - SHA512(hmg,sig + 32,64); + SHA512(hmg, sig + 32, 64); - /* Computation of R */ - sc25519_from64bytes(&sck, hmg); - ge25519_scalarmult_base(&ger, &sck); - ge25519_pack(r, &ger); + /* Computation of R */ + sc25519_from64bytes(&sck, hmg); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(r, &ger); - /* Computation of s */ - for(unsigned int i=0;i<32;i++) - sig[i] = r[i]; + /* Computation of s */ + for (unsigned int i = 0; i < 32; i++) + sig[i] = r[i]; - get_hram(hram,sig,myPublic + 32,sig,96); + get_hram(hram, sig, myPublic + 32, sig, 96); - sc25519_from64bytes(&scs, hram); - sc25519_from32bytes(&scsk, extsk); - sc25519_mul(&scs, &scs, &scsk); + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, extsk); + sc25519_mul(&scs, &scs, &scsk); - sc25519_add(&scs, &scs, &sck); + sc25519_add(&scs, &scs, &sck); - sc25519_to32bytes(s,&scs); /* cat s */ - for(unsigned int i=0;i<32;i++) - sig[32 + i] = s[i]; + sc25519_to32bytes(s, &scs); /* cat s */ + for (unsigned int i = 0; i < 32; i++) + sig[32 + i] = s[i]; } -bool C25519::verify(const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,const void *signature,const unsigned int siglen) +bool C25519::verify( + const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + const void* msg, + unsigned int len, + const void* signature, + const unsigned int siglen) { - if (siglen < 64) return false; + if (siglen < 64) + return false; - const unsigned char *sig = (const unsigned char *)signature; - unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) - unsigned char sigtmp[96]; - SHA512(digest,msg,len); + const unsigned char* sig = (const unsigned char*)signature; + unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) + unsigned char sigtmp[96]; + SHA512(digest, msg, len); - if ((siglen == 96)&&(!Utils::secureEq(sig+64,digest,32))) { - return false; - } else if (siglen == 64) { - Utils::copy<64>(sigtmp,sig); - Utils::copy<32>(sigtmp+64,digest); - sig = sigtmp; - } + if ((siglen == 96) && (! Utils::secureEq(sig + 64, digest, 32))) { + return false; + } + else if (siglen == 64) { + Utils::copy<64>(sigtmp, sig); + Utils::copy<32>(sigtmp + 64, digest); + sig = sigtmp; + } - unsigned char t2[32]; - ge25519 get1, get2; - sc25519 schram, scs; - unsigned char hram[crypto_hash_sha512_BYTES]; - unsigned char m[96]; + unsigned char t2[32]; + ge25519 get1, get2; + sc25519 schram, scs; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned char m[96]; - if (ge25519_unpackneg_vartime(&get1,their + 32)) - return false; + if (ge25519_unpackneg_vartime(&get1, their + 32)) + return false; - get_hram(hram,sig,their + 32,m,96); + get_hram(hram, sig, their + 32, m, 96); - sc25519_from64bytes(&schram, hram); + sc25519_from64bytes(&schram, hram); - sc25519_from32bytes(&scs, sig+32); + sc25519_from32bytes(&scs, sig + 32); - ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs); - ge25519_pack(t2, &get2); + ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs); + ge25519_pack(t2, &get2); - return Utils::secureEq(sig,t2,32); + return Utils::secureEq(sig, t2, 32); } -void C25519::s_calcPubDH(uint8_t *pub, const uint8_t *priv) +void C25519::s_calcPubDH(uint8_t* pub, const uint8_t* priv) { - // First 32 bytes of pub and priv are the keys for ECDH key - // agreement. This generates the public portion from the private. - crypto_scalarmult_base(pub,priv); + // First 32 bytes of pub and priv are the keys for ECDH key + // agreement. This generates the public portion from the private. + crypto_scalarmult_base(pub, priv); } -void C25519::s_calcPubED(uint8_t *pub, const uint8_t *priv) +void C25519::s_calcPubED(uint8_t* pub, const uint8_t* priv) { - struct { - uint8_t extsk[64]; - sc25519 scsk; - ge25519 gepk; - } s; + struct { + uint8_t extsk[64]; + sc25519 scsk; + ge25519 gepk; + } s; - // Second 32 bytes of pub and priv are the keys for ed25519 - // signing and verification. - SHA512(s.extsk,priv + 32,32); - s.extsk[0] &= 248U; - s.extsk[31] &= 127U; - s.extsk[31] |= 64U; - sc25519_from32bytes(&s.scsk,s.extsk); - ge25519_scalarmult_base(&s.gepk,&s.scsk); - ge25519_pack(pub + 32,&s.gepk); + // Second 32 bytes of pub and priv are the keys for ed25519 + // signing and verification. + SHA512(s.extsk, priv + 32, 32); + s.extsk[0] &= 248U; + s.extsk[31] &= 127U; + s.extsk[31] |= 64U; + sc25519_from32bytes(&s.scsk, s.extsk); + ge25519_scalarmult_base(&s.gepk, &s.scsk); + ge25519_pack(pub + 32, &s.gepk); - // In NaCl, the public key is crammed into the next 32 bytes - // of the private key for signing since both keys are required - // to sign. In this version we just get it from kp.pub, so we - // leave that out of private. + // In NaCl, the public key is crammed into the next 32 bytes + // of the private key for signing since both keys are required + // to sign. In this version we just get it from kp.pub, so we + // leave that out of private. - Utils::burn(&s,sizeof(s)); + Utils::burn(&s, sizeof(s)); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/C25519.hpp b/core/C25519.hpp index 24a3ac569..f9411c2ad 100644 --- a/core/C25519.hpp +++ b/core/C25519.hpp @@ -25,107 +25,125 @@ namespace ZeroTier { -#define ZT_C25519_ECDH_PUBLIC_KEY_SIZE 32 -#define ZT_C25519_ECDH_PRIVATE_KEY_SIZE 32 -#define ZT_C25519_COMBINED_PUBLIC_KEY_SIZE 64 +#define ZT_C25519_ECDH_PUBLIC_KEY_SIZE 32 +#define ZT_C25519_ECDH_PRIVATE_KEY_SIZE 32 +#define ZT_C25519_COMBINED_PUBLIC_KEY_SIZE 64 #define ZT_C25519_COMBINED_PRIVATE_KEY_SIZE 64 -#define ZT_C25519_SIGNATURE_LEN 96 -#define ZT_C25519_ECDH_SHARED_SECRET_SIZE 32 +#define ZT_C25519_SIGNATURE_LEN 96 +#define ZT_C25519_ECDH_SHARED_SECRET_SIZE 32 /** * A combined Curve25519 ECDH and Ed25519 signature engine */ -class C25519 -{ -public: - /** - * Generate a set of two 25519 keys: a C25519 ECDH key pair and an Ed25519 EDDSA key pair. - */ - static void generateCombined(uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]); +class C25519 { + public: + /** + * Generate a set of two 25519 keys: a C25519 ECDH key pair and an Ed25519 EDDSA key pair. + */ + static void generateCombined( + uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]); - /** - * Generate a C25519 ECDH key pair only. - */ - static void generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]); + /** + * Generate a C25519 ECDH key pair only. + */ + static void + generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE], uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]); - /** - * Generate a key pair satisfying a condition - * - * This begins with a random keypair from a random secret key and then - * iteratively increments the random secret until cond(kp) returns true. - * This is used to compute key pairs in which the public key, its hash - * or some other aspect of it satisfies some condition, such as for a - * hashcash criteria. - * - * @param cond Condition function or function object - * @return Key pair where cond(kp) returns true - * @tparam F Type of 'cond' - */ - template - static ZT_INLINE void generateSatisfying(F cond,uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]) - { - Utils::getSecureRandom(priv,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); - s_calcPubED(pub, priv); // do Ed25519 key -- bytes 32-63 of pub and priv - do { - ++(((uint64_t *)priv)[1]); - --(((uint64_t *)priv)[2]); - s_calcPubDH(pub, priv); // keep regenerating bytes 0-31 until satisfied - } while (!cond(pub)); - } + /** + * Generate a key pair satisfying a condition + * + * This begins with a random keypair from a random secret key and then + * iteratively increments the random secret until cond(kp) returns true. + * This is used to compute key pairs in which the public key, its hash + * or some other aspect of it satisfies some condition, such as for a + * hashcash criteria. + * + * @param cond Condition function or function object + * @return Key pair where cond(kp) returns true + * @tparam F Type of 'cond' + */ + template + static ZT_INLINE void generateSatisfying( + F cond, + uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]) + { + Utils::getSecureRandom(priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + s_calcPubED(pub, priv); // do Ed25519 key -- bytes 32-63 of pub and priv + do { + ++(((uint64_t*)priv)[1]); + --(((uint64_t*)priv)[2]); + s_calcPubDH(pub, priv); // keep regenerating bytes 0-31 until satisfied + } while (! cond(pub)); + } - /** - * Perform C25519 ECC key agreement - * - * Actual key bytes are generated from one or more SHA-512 digests of - * the raw result of key agreement. - * - * @param mine My private key - * @param their Their public key - * @param rawkey Buffer to receive raw (not hashed) agreed upon key - */ - static void agree(const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE],const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]); + /** + * Perform C25519 ECC key agreement + * + * Actual key bytes are generated from one or more SHA-512 digests of + * the raw result of key agreement. + * + * @param mine My private key + * @param their Their public key + * @param rawkey Buffer to receive raw (not hashed) agreed upon key + */ + static void agree( + const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE], + const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE], + uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]); - /** - * Sign a message with a sender's key pair - * - * LEGACY: ZeroTier's ed25519 signatures contain an extra 32 bytes which are the first - * 32 bytes of SHA512(msg). These exist because an early version of the ZeroTier multicast - * algorithm did a lot of signature verification and we wanted a way to skip the more - * expensive ed25519 verification if the signature was obviously wrong. - * - * This verify() function will accept a 64 or 96 bit signature, checking the last 32 - * bytes only if present. - * - * @param myPrivate My private key - * @param myPublic My public key - * @param msg Message to sign - * @param len Length of message in bytes - * @param signature Buffer to fill with signature -- MUST be 96 bytes in length - */ - static void sign(const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,void *signature); + /** + * Sign a message with a sender's key pair + * + * LEGACY: ZeroTier's ed25519 signatures contain an extra 32 bytes which are the first + * 32 bytes of SHA512(msg). These exist because an early version of the ZeroTier multicast + * algorithm did a lot of signature verification and we wanted a way to skip the more + * expensive ed25519 verification if the signature was obviously wrong. + * + * This verify() function will accept a 64 or 96 bit signature, checking the last 32 + * bytes only if present. + * + * @param myPrivate My private key + * @param myPublic My public key + * @param msg Message to sign + * @param len Length of message in bytes + * @param signature Buffer to fill with signature -- MUST be 96 bytes in length + */ + static void sign( + const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE], + const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + const void* msg, + unsigned int len, + void* signature); - /** - * Verify a message's signature - * - * @param their Public key to verify against - * @param msg Message to verify signature integrity against - * @param len Length of message in bytes - * @param signature Signature bytes - * @param siglen Length of signature in bytes - * @return True if signature is valid and the message is authentic and unmodified - */ - static bool verify(const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,const void *signature,unsigned int siglen); + /** + * Verify a message's signature + * + * @param their Public key to verify against + * @param msg Message to verify signature integrity against + * @param len Length of message in bytes + * @param signature Signature bytes + * @param siglen Length of signature in bytes + * @return True if signature is valid and the message is authentic and unmodified + */ + static bool verify( + const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE], + const void* msg, + unsigned int len, + const void* signature, + unsigned int siglen); -private: - // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv - // this is the ECDH key - static void s_calcPubDH(uint8_t *pub, const uint8_t *priv); + private: + // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv + // this is the ECDH key + static void s_calcPubDH(uint8_t* pub, const uint8_t* priv); - // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv - // this is the Ed25519 sign/verify key - static void s_calcPubED(uint8_t *pub, const uint8_t *priv); + // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv + // this is the Ed25519 sign/verify key + static void s_calcPubED(uint8_t* pub, const uint8_t* priv); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/CAPI.cpp b/core/CAPI.cpp index 21bdda857..a23ba75b7 100644 --- a/core/CAPI.cpp +++ b/core/CAPI.cpp @@ -11,16 +11,16 @@ */ /****/ -#include "Constants.hpp" -#include "Node.hpp" -#include "Identity.hpp" -#include "Locator.hpp" +#include "CallContext.hpp" #include "Certificate.hpp" +#include "Constants.hpp" +#include "ECC384.hpp" +#include "Identity.hpp" #include "InetAddress.hpp" +#include "Locator.hpp" +#include "Node.hpp" #include "VL1.hpp" #include "VL2.hpp" -#include "CallContext.hpp" -#include "ECC384.hpp" extern "C" { @@ -29,970 +29,1035 @@ extern "C" { // These macros make the idiom of passing buffers to outside code via the API work properly even // if the first address of Buf does not overlap with its data field, since the C++ standard does // not absolutely guarantee this. -#define ZT_PTRTOBUF(p) ((ZeroTier::Buf *)( ((uintptr_t)(p)) - ((uintptr_t)&(((ZeroTier::Buf *)0)->unsafeData[0])) )) -#define ZT_BUFTOPTR(b) ((void *)(&((b)->unsafeData[0]))) +#define ZT_PTRTOBUF(p) ((ZeroTier::Buf*)(((uintptr_t)(p)) - ((uintptr_t) & (((ZeroTier::Buf*)0)->unsafeData[0])))) +#define ZT_BUFTOPTR(b) ((void*)(&((b)->unsafeData[0]))) -ZT_MAYBE_UNUSED void *ZT_getBuffer() +ZT_MAYBE_UNUSED void* ZT_getBuffer() { - // When external code requests a Buf, grab one from the pool (or freshly allocated) - // and return it with its reference count left at zero. It's the responsibility of - // external code to bring it back via freeBuffer() or one of the processX() calls. - // When this occurs it's either sent back to the pool with Buf's delete operator or - // wrapped in a SharedPtr<> to be passed into the core. - try { - return ZT_BUFTOPTR(new ZeroTier::Buf()); - } catch (...) { - return nullptr; // can only happen on out of memory condition - } + // When external code requests a Buf, grab one from the pool (or freshly allocated) + // and return it with its reference count left at zero. It's the responsibility of + // external code to bring it back via freeBuffer() or one of the processX() calls. + // When this occurs it's either sent back to the pool with Buf's delete operator or + // wrapped in a SharedPtr<> to be passed into the core. + try { + return ZT_BUFTOPTR(new ZeroTier::Buf()); + } + catch (...) { + return nullptr; // can only happen on out of memory condition + } } -ZT_MAYBE_UNUSED void ZT_freeBuffer(void *b) +ZT_MAYBE_UNUSED void ZT_freeBuffer(void* b) { - if (b) - delete ZT_PTRTOBUF(b); + if (b) + delete ZT_PTRTOBUF(b); } -struct p_queryResultBase -{ - void (*freeFunction)(const void *); +struct p_queryResultBase { + void (*freeFunction)(const void*); }; -ZT_MAYBE_UNUSED void ZT_freeQueryResult(const void *qr) +ZT_MAYBE_UNUSED void ZT_freeQueryResult(const void* qr) { - if ((qr) && (reinterpret_cast(qr)->freeFunction)) - reinterpret_cast(qr)->freeFunction(qr); + if ((qr) && (reinterpret_cast(qr)->freeFunction)) + reinterpret_cast(qr)->freeFunction(qr); } -ZT_MAYBE_UNUSED void ZT_version(int *major, int *minor, int *revision, int *build) +ZT_MAYBE_UNUSED void ZT_version(int* major, int* minor, int* revision, int* build) { - if (major) - *major = ZEROTIER_VERSION_MAJOR; - if (minor) - *minor = ZEROTIER_VERSION_MINOR; - if (revision) - *revision = ZEROTIER_VERSION_REVISION; - if (build) - *build = ZEROTIER_VERSION_BUILD; + if (major) + *major = ZEROTIER_VERSION_MAJOR; + if (minor) + *minor = ZEROTIER_VERSION_MINOR; + if (revision) + *revision = ZEROTIER_VERSION_REVISION; + if (build) + *build = ZEROTIER_VERSION_BUILD; } /********************************************************************************************************************/ ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - int64_t clock, - int64_t ticks, - void *tptr, - void *uptr, - const struct ZT_Node_Callbacks *callbacks) + ZT_Node** node, + int64_t clock, + int64_t ticks, + void* tptr, + void* uptr, + const struct ZT_Node_Callbacks* callbacks) { - *node = nullptr; - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - *node = reinterpret_cast(new ZeroTier::Node(uptr, callbacks, cc)); - return ZT_RESULT_OK; - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (std::runtime_error &exc) { - return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + *node = nullptr; + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + *node = reinterpret_cast(new ZeroTier::Node(uptr, callbacks, cc)); + return ZT_RESULT_OK; + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (std::runtime_error& exc) { + return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED void ZT_Node_delete( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr) +ZT_MAYBE_UNUSED void ZT_Node_delete(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - reinterpret_cast(node)->shutdown(cc); - delete (reinterpret_cast(node)); - } catch (...) {} + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + reinterpret_cast(node)->shutdown(cc); + delete (reinterpret_cast(node)); + } + catch (...) { + } } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - int64_t localSocket, - const ZT_InetAddress *remoteAddress, - const void *packetData, - unsigned int packetLength, - int isZtBuffer, - volatile int64_t *) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + int64_t localSocket, + const ZT_InetAddress* remoteAddress, + const void* packetData, + unsigned int packetLength, + int isZtBuffer, + volatile int64_t*) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK)); - reinterpret_cast(node)->context().vl1->onRemotePacket(cc, localSocket, *ZeroTier::asInetAddress(remoteAddress), buf, packetLength); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - // "OK" since invalid packets are simply dropped, but the system is still up. - // We should never make it here, but if we did that would be the interpretation. - } - return ZT_RESULT_OK; + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + ZeroTier::SharedPtr buf( + (isZtBuffer) ? ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK)); + reinterpret_cast(node) + ->context() + .vl1->onRemotePacket(cc, localSocket, *ZeroTier::asInetAddress(remoteAddress), buf, packetLength); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + // "OK" since invalid packets are simply dropped, but the system is still up. + // We should never make it here, but if we did that would be the interpretation. + } + return ZT_RESULT_OK; } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - int isZtBuffer, - volatile int64_t *) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + int isZtBuffer, + volatile int64_t*) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - const ZeroTier::Context &ctx = reinterpret_cast(node)->context(); - ZeroTier::SharedPtr< ZeroTier::Network > network(ctx.networks->get(nwid)); - if (likely(network)) { - ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData, frameLength & ZT_BUF_MEM_MASK)); - ctx.vl2->onLocalEthernet(cc, network, ZeroTier::MAC(sourceMac), ZeroTier::MAC(destMac), etherType, vlanId, buf, frameLength); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + const ZeroTier::Context& ctx = reinterpret_cast(node)->context(); + ZeroTier::SharedPtr network(ctx.networks->get(nwid)); + if (likely(network)) { + ZeroTier::SharedPtr buf( + (isZtBuffer) ? ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData, frameLength & ZT_BUF_MEM_MASK)); + ctx.vl2->onLocalEthernet( + cc, + network, + ZeroTier::MAC(sourceMac), + ZeroTier::MAC(destMac), + etherType, + vlanId, + buf, + frameLength); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_processBackgroundTasks( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - volatile int64_t *nextBackgroundTaskDeadline) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + volatile int64_t* nextBackgroundTaskDeadline) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->processBackgroundTasks(cc, nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->processBackgroundTasks(cc, nextBackgroundTaskDeadline); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_join( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - void *uptr, - uint64_t nwid, - const ZT_Fingerprint *controllerFingerprint) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + void* uptr, + uint64_t nwid, + const ZT_Fingerprint* controllerFingerprint) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->join(nwid, controllerFingerprint, uptr, cc); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->join(nwid, controllerFingerprint, uptr, cc); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_leave( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - void **uptr, - uint64_t nwid) +ZT_MAYBE_UNUSED enum ZT_ResultCode +ZT_Node_leave(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, void** uptr, uint64_t nwid) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->leave(nwid, uptr, cc); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->leave(nwid, uptr, cc); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_multicastSubscribe( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t multicastGroup, + unsigned long multicastAdi) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->multicastSubscribe(cc, nwid, multicastGroup, multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->multicastSubscribe(cc, nwid, multicastGroup, multicastAdi); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_multicastUnsubscribe( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t multicastGroup, + unsigned long multicastAdi) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->multicastUnsubscribe(cc, nwid, multicastGroup, multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->multicastUnsubscribe(cc, nwid, multicastGroup, multicastAdi); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED uint64_t ZT_Node_address(ZT_Node *node) -{ return reinterpret_cast(node)->context().identity.address().toInt(); } - -ZT_MAYBE_UNUSED const ZT_Identity *ZT_Node_identity(ZT_Node *node) -{ return (const ZT_Identity *)(&(reinterpret_cast(node)->identity())); } - -ZT_MAYBE_UNUSED void ZT_Node_status( - ZT_Node *node, - int64_t, - int64_t, - void *, - ZT_NodeStatus *status) +ZT_MAYBE_UNUSED uint64_t ZT_Node_address(ZT_Node* node) { - try { - reinterpret_cast(node)->status(status); - } catch (...) {} + return reinterpret_cast(node)->context().identity.address().toInt(); } -ZT_MAYBE_UNUSED ZT_PeerList *ZT_Node_peers( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr) +ZT_MAYBE_UNUSED const ZT_Identity* ZT_Node_identity(ZT_Node* node) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->peers(cc); - } catch (...) { - return (ZT_PeerList *)0; - } + return (const ZT_Identity*)(&(reinterpret_cast(node)->identity())); } -ZT_MAYBE_UNUSED ZT_VirtualNetworkConfig *ZT_Node_networkConfig( - ZT_Node *node, - int64_t, - int64_t, - void *, - uint64_t nwid) +ZT_MAYBE_UNUSED void ZT_Node_status(ZT_Node* node, int64_t, int64_t, void*, ZT_NodeStatus* status) { - try { - return reinterpret_cast(node)->networkConfig(nwid); - } catch (...) { - return (ZT_VirtualNetworkConfig *)0; - } + try { + reinterpret_cast(node)->status(status); + } + catch (...) { + } } -ZT_MAYBE_UNUSED ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node) +ZT_MAYBE_UNUSED ZT_PeerList* ZT_Node_peers(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr) { - try { - return reinterpret_cast(node)->networks(); - } catch (...) { - return (ZT_VirtualNetworkList *)0; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->peers(cc); + } + catch (...) { + return (ZT_PeerList*)0; + } } -ZT_MAYBE_UNUSED void ZT_Node_setNetworkUserPtr( - ZT_Node *node, - uint64_t nwid, - void *ptr) +ZT_MAYBE_UNUSED ZT_VirtualNetworkConfig* ZT_Node_networkConfig(ZT_Node* node, int64_t, int64_t, void*, uint64_t nwid) { - try { - reinterpret_cast(node)->setNetworkUserPtr(nwid, ptr); - } catch (...) {} + try { + return reinterpret_cast(node)->networkConfig(nwid); + } + catch (...) { + return (ZT_VirtualNetworkConfig*)0; + } +} + +ZT_MAYBE_UNUSED ZT_VirtualNetworkList* ZT_Node_networks(ZT_Node* node) +{ + try { + return reinterpret_cast(node)->networks(); + } + catch (...) { + return (ZT_VirtualNetworkList*)0; + } +} + +ZT_MAYBE_UNUSED void ZT_Node_setNetworkUserPtr(ZT_Node* node, uint64_t nwid, void* ptr) +{ + try { + reinterpret_cast(node)->setNetworkUserPtr(nwid, ptr); + } + catch (...) { + } } ZT_MAYBE_UNUSED void ZT_Node_setInterfaceAddresses( - ZT_Node *node, - int64_t, - int64_t, - void *, - const ZT_InterfaceAddress *addrs, - unsigned int addrCount) + ZT_Node* node, + int64_t, + int64_t, + void*, + const ZT_InterfaceAddress* addrs, + unsigned int addrCount) { - try { - reinterpret_cast(node)->setInterfaceAddresses(addrs, addrCount); - } catch (...) {} + try { + reinterpret_cast(node)->setInterfaceAddresses(addrs, addrCount); + } + catch (...) { + } } ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Node_addCertificate( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - unsigned int localTrust, - const ZT_Certificate *cert, - const void *certData, - unsigned int certSize) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + unsigned int localTrust, + const ZT_Certificate* cert, + const void* certData, + unsigned int certSize) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->addCertificate(cc, localTrust, cert, certData, certSize); - } catch (...) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->addCertificate(cc, localTrust, cert, certData, certSize); + } + catch (...) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } } -ZT_MAYBE_UNUSED enum ZT_ResultCode ZT_Node_deleteCertificate( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - const void *serialNo) +ZT_MAYBE_UNUSED enum ZT_ResultCode +ZT_Node_deleteCertificate(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, const void* serialNo) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->deleteCertificate(cc, serialNo); - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->deleteCertificate(cc, serialNo); + } + catch (...) { + return ZT_RESULT_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED ZT_CertificateList *ZT_Node_listCertificates( - ZT_Node *node, - int64_t, - int64_t, - void *) +ZT_MAYBE_UNUSED ZT_CertificateList* ZT_Node_listCertificates(ZT_Node* node, int64_t, int64_t, void*) { - try { - return reinterpret_cast(node)->listCertificates(); - } catch (...) { - return nullptr; - } + try { + return reinterpret_cast(node)->listCertificates(); + } + catch (...) { + return nullptr; + } } ZT_MAYBE_UNUSED int ZT_Node_sendUserMessage( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t dest, - uint64_t typeId, - const void *data, - unsigned int len) + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t dest, + uint64_t typeId, + const void* data, + unsigned int len) { - try { - ZeroTier::CallContext cc(clock, ticks, tptr); - return reinterpret_cast(node)->sendUserMessage(cc, dest, typeId, data, len); - } catch (...) { - return 0; - } + try { + ZeroTier::CallContext cc(clock, ticks, tptr); + return reinterpret_cast(node)->sendUserMessage(cc, dest, typeId, data, len); + } + catch (...) { + return 0; + } } -ZT_MAYBE_UNUSED void ZT_Node_setController( - ZT_Node *node, - void *networkControllerInstance) +ZT_MAYBE_UNUSED void ZT_Node_setController(ZT_Node* node, void* networkControllerInstance) { - try { - reinterpret_cast(node)->setController(networkControllerInstance); - } catch (...) {} + try { + reinterpret_cast(node)->setController(networkControllerInstance); + } + catch (...) { + } } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED ZT_Locator *ZT_Locator_create( - int64_t rev, - const ZT_Endpoint *endpoints, - const ZT_EndpointAttributes *, - unsigned int endpointCount, - const ZT_Identity *signer) +ZT_MAYBE_UNUSED ZT_Locator* ZT_Locator_create( + int64_t rev, + const ZT_Endpoint* endpoints, + const ZT_EndpointAttributes*, + unsigned int endpointCount, + const ZT_Identity* signer) { - try { - if ((!endpoints) || (endpointCount == 0) || (!signer)) - return nullptr; - ZeroTier::Locator *loc = new ZeroTier::Locator(); - for (unsigned int i = 0;i < endpointCount;++i) - loc->add(reinterpret_cast< const ZeroTier::Endpoint * >(endpoints)[i], ZeroTier::Locator::EndpointAttributes::DEFAULT); - if (!loc->sign(rev, *reinterpret_cast< const ZeroTier::Identity * >(signer))) { - delete loc; - return nullptr; - } - return reinterpret_cast(loc); - } catch (...) { - return nullptr; - } + try { + if ((! endpoints) || (endpointCount == 0) || (! signer)) + return nullptr; + ZeroTier::Locator* loc = new ZeroTier::Locator(); + for (unsigned int i = 0; i < endpointCount; ++i) + loc->add( + reinterpret_cast(endpoints)[i], + ZeroTier::Locator::EndpointAttributes::DEFAULT); + if (! loc->sign(rev, *reinterpret_cast(signer))) { + delete loc; + return nullptr; + } + return reinterpret_cast(loc); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED ZT_Locator *ZT_Locator_fromString(const char *str) +ZT_MAYBE_UNUSED ZT_Locator* ZT_Locator_fromString(const char* str) { - try { - if (!str) - return nullptr; - ZeroTier::Locator *loc = new ZeroTier::Locator(); - if (!loc->fromString(str)) { - delete loc; - return nullptr; - } - return reinterpret_cast(loc); - } catch ( ... ) { - return nullptr; - } + try { + if (! str) + return nullptr; + ZeroTier::Locator* loc = new ZeroTier::Locator(); + if (! loc->fromString(str)) { + delete loc; + return nullptr; + } + return reinterpret_cast(loc); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED ZT_Locator *ZT_Locator_unmarshal( - const void *data, - unsigned int len) +ZT_MAYBE_UNUSED ZT_Locator* ZT_Locator_unmarshal(const void* data, unsigned int len) { - try { - if ((!data) || (len == 0)) - return nullptr; - ZeroTier::Locator *loc = new ZeroTier::Locator(); - if (loc->unmarshal(reinterpret_cast(data), (int) len) <= 0) { - delete loc; - return nullptr; - } - return reinterpret_cast(loc); - } catch (...) { - return nullptr; - } + try { + if ((! data) || (len == 0)) + return nullptr; + ZeroTier::Locator* loc = new ZeroTier::Locator(); + if (loc->unmarshal(reinterpret_cast(data), (int)len) <= 0) { + delete loc; + return nullptr; + } + return reinterpret_cast(loc); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED int ZT_Locator_marshal(const ZT_Locator *loc, void *buf, unsigned int bufSize) +ZT_MAYBE_UNUSED int ZT_Locator_marshal(const ZT_Locator* loc, void* buf, unsigned int bufSize) { - if ((!loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX)) - return -1; - return reinterpret_cast(loc)->marshal(reinterpret_cast(buf), false); + if ((! loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX)) + return -1; + return reinterpret_cast(loc)->marshal(reinterpret_cast(buf), false); } -ZT_MAYBE_UNUSED char *ZT_Locator_toString( - const ZT_Locator *loc, - char *buf, - int capacity) +ZT_MAYBE_UNUSED char* ZT_Locator_toString(const ZT_Locator* loc, char* buf, int capacity) { - if ((!loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX)) - return nullptr; - return reinterpret_cast(loc)->toString(buf); + if ((! loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX)) + return nullptr; + return reinterpret_cast(loc)->toString(buf); } -ZT_MAYBE_UNUSED int64_t ZT_Locator_revision(const ZT_Locator *loc) +ZT_MAYBE_UNUSED int64_t ZT_Locator_revision(const ZT_Locator* loc) { - if (!loc) - return 0; - return reinterpret_cast(loc)->revision(); + if (! loc) + return 0; + return reinterpret_cast(loc)->revision(); } -ZT_MAYBE_UNUSED uint64_t ZT_Locator_signer(const ZT_Locator *loc) +ZT_MAYBE_UNUSED uint64_t ZT_Locator_signer(const ZT_Locator* loc) { - if (!loc) - return 0; - return reinterpret_cast(loc)->signer().toInt(); + if (! loc) + return 0; + return reinterpret_cast(loc)->signer().toInt(); } -ZT_MAYBE_UNUSED int ZT_Locator_equals(const ZT_Locator *a, const ZT_Locator *b) +ZT_MAYBE_UNUSED int ZT_Locator_equals(const ZT_Locator* a, const ZT_Locator* b) { - if (a) { - if (b) { - if (*reinterpret_cast(a) == *reinterpret_cast(b)) - return 1; - } - } else if (!b) { - return 1; - } - return 0; + if (a) { + if (b) { + if (*reinterpret_cast(a) == *reinterpret_cast(b)) + return 1; + } + } + else if (! b) { + return 1; + } + return 0; } -ZT_MAYBE_UNUSED unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc) -{ return (loc) ? (unsigned int) (reinterpret_cast(loc)->endpoints().size()) : 0; } - -ZT_MAYBE_UNUSED const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc, const unsigned int ep) +ZT_MAYBE_UNUSED unsigned int ZT_Locator_endpointCount(const ZT_Locator* loc) { - if (!loc) - return nullptr; - if (ep >= (unsigned int) (reinterpret_cast(loc)->endpoints().size())) - return nullptr; - return reinterpret_cast(&(reinterpret_cast(loc)->endpoints()[ep])); + return (loc) ? (unsigned int)(reinterpret_cast(loc)->endpoints().size()) : 0; } -ZT_MAYBE_UNUSED int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer) +ZT_MAYBE_UNUSED const ZT_Endpoint* ZT_Locator_endpoint(const ZT_Locator* loc, const unsigned int ep) { - if ((!loc) || (!signer)) - return 0; - return reinterpret_cast(loc)->verify(*reinterpret_cast(signer)) ? 1 : 0; + if (! loc) + return nullptr; + if (ep >= (unsigned int)(reinterpret_cast(loc)->endpoints().size())) + return nullptr; + return reinterpret_cast(&(reinterpret_cast(loc)->endpoints()[ep])); } -ZT_MAYBE_UNUSED void ZT_Locator_delete(const ZT_Locator *loc) +ZT_MAYBE_UNUSED int ZT_Locator_verify(const ZT_Locator* loc, const ZT_Identity* signer) { - if (loc) - delete reinterpret_cast(loc); + if ((! loc) || (! signer)) + return 0; + return reinterpret_cast(loc)->verify(*reinterpret_cast(signer)) + ? 1 + : 0; +} + +ZT_MAYBE_UNUSED void ZT_Locator_delete(const ZT_Locator* loc) +{ + if (loc) + delete reinterpret_cast(loc); } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type) +ZT_MAYBE_UNUSED ZT_Identity* ZT_Identity_new(enum ZT_IdentityType type) { - if ((type != ZT_IDENTITY_TYPE_C25519) && (type != ZT_IDENTITY_TYPE_P384)) - return nullptr; - try { - ZeroTier::Identity *const id = new ZeroTier::Identity(); - id->generate((ZeroTier::Identity::Type)type); - return reinterpret_cast(id); - } catch (...) { - return nullptr; - } + if ((type != ZT_IDENTITY_TYPE_C25519) && (type != ZT_IDENTITY_TYPE_P384)) + return nullptr; + try { + ZeroTier::Identity* const id = new ZeroTier::Identity(); + id->generate((ZeroTier::Identity::Type)type); + return reinterpret_cast(id); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED ZT_Identity *ZT_Identity_clone(const ZT_Identity *id) +ZT_MAYBE_UNUSED ZT_Identity* ZT_Identity_clone(const ZT_Identity* id) { - if (id) { - try { - return reinterpret_cast(new ZeroTier::Identity(*reinterpret_cast(id))); - } catch ( ... ) { - return nullptr; - } - } - return nullptr; + if (id) { + try { + return reinterpret_cast( + new ZeroTier::Identity(*reinterpret_cast(id))); + } + catch (...) { + return nullptr; + } + } + return nullptr; } -ZT_MAYBE_UNUSED ZT_Identity *ZT_Identity_fromString(const char *idStr) +ZT_MAYBE_UNUSED ZT_Identity* ZT_Identity_fromString(const char* idStr) { - if (!idStr) - return nullptr; - try { - ZeroTier::Identity *const id = new ZeroTier::Identity(); - if (!id->fromString(idStr)) { - delete id; - return nullptr; - } - return reinterpret_cast(id); - } catch (...) { - return nullptr; - } + if (! idStr) + return nullptr; + try { + ZeroTier::Identity* const id = new ZeroTier::Identity(); + if (! id->fromString(idStr)) { + delete id; + return nullptr; + } + return reinterpret_cast(id); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED int ZT_Identity_validate(const ZT_Identity *id) +ZT_MAYBE_UNUSED int ZT_Identity_validate(const ZT_Identity* id) { - if (!id) - return 0; - return reinterpret_cast(id)->locallyValidate() ? 1 : 0; + if (! id) + return 0; + return reinterpret_cast(id)->locallyValidate() ? 1 : 0; } -ZT_MAYBE_UNUSED unsigned int ZT_Identity_sign(const ZT_Identity *id, const void *data, unsigned int len, void *signature, unsigned int signatureBufferLength) +ZT_MAYBE_UNUSED unsigned int ZT_Identity_sign( + const ZT_Identity* id, + const void* data, + unsigned int len, + void* signature, + unsigned int signatureBufferLength) { - if (!id) - return 0; - if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE) - return 0; - return reinterpret_cast(id)->sign(data, len, signature, signatureBufferLength); + if (! id) + return 0; + if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE) + return 0; + return reinterpret_cast(id)->sign(data, len, signature, signatureBufferLength); } -ZT_MAYBE_UNUSED int ZT_Identity_verify(const ZT_Identity *id, const void *data, unsigned int len, const void *signature, unsigned int sigLen) +ZT_MAYBE_UNUSED int ZT_Identity_verify( + const ZT_Identity* id, + const void* data, + unsigned int len, + const void* signature, + unsigned int sigLen) { - if ((!id) || (!signature) || (!sigLen)) - return 0; - return reinterpret_cast(id)->verify(data, len, signature, sigLen) ? 1 : 0; + if ((! id) || (! signature) || (! sigLen)) + return 0; + return reinterpret_cast(id)->verify(data, len, signature, sigLen) ? 1 : 0; } -ZT_MAYBE_UNUSED enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id) +ZT_MAYBE_UNUSED enum ZT_IdentityType ZT_Identity_type(const ZT_Identity* id) { - if (!id) - return (ZT_IdentityType)0; - return (enum ZT_IdentityType)reinterpret_cast(id)->type(); + if (! id) + return (ZT_IdentityType)0; + return (enum ZT_IdentityType) reinterpret_cast(id)->type(); } -ZT_MAYBE_UNUSED char *ZT_Identity_toString(const ZT_Identity *id, char *buf, int capacity, int includePrivate) +ZT_MAYBE_UNUSED char* ZT_Identity_toString(const ZT_Identity* id, char* buf, int capacity, int includePrivate) { - if ((!id) || (!buf) || (capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH)) - return nullptr; - reinterpret_cast(id)->toString(includePrivate != 0, buf); - return buf; + if ((! id) || (! buf) || (capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH)) + return nullptr; + reinterpret_cast(id)->toString(includePrivate != 0, buf); + return buf; } -ZT_MAYBE_UNUSED int ZT_Identity_hasPrivate(const ZT_Identity *id) +ZT_MAYBE_UNUSED int ZT_Identity_hasPrivate(const ZT_Identity* id) { - if (!id) - return 0; - return reinterpret_cast(id)->hasPrivate() ? 1 : 0; + if (! id) + return 0; + return reinterpret_cast(id)->hasPrivate() ? 1 : 0; } -ZT_MAYBE_UNUSED uint64_t ZT_Identity_address(const ZT_Identity *id) +ZT_MAYBE_UNUSED uint64_t ZT_Identity_address(const ZT_Identity* id) { - if (!id) - return 0; - return reinterpret_cast(id)->address(); + if (! id) + return 0; + return reinterpret_cast(id)->address(); } -ZT_MAYBE_UNUSED const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id) +ZT_MAYBE_UNUSED const ZT_Fingerprint* ZT_Identity_fingerprint(const ZT_Identity* id) { - if (!id) - return nullptr; - return &(reinterpret_cast(id)->fingerprint()); + if (! id) + return nullptr; + return &(reinterpret_cast(id)->fingerprint()); } -ZT_MAYBE_UNUSED int ZT_Identity_compare(const ZT_Identity *a, const ZT_Identity *b) +ZT_MAYBE_UNUSED int ZT_Identity_compare(const ZT_Identity* a, const ZT_Identity* b) { - if (a) { - if (b) { - if (*reinterpret_cast(a) < *reinterpret_cast(b)) { - return -1; - } else if (*reinterpret_cast(b) < *reinterpret_cast(a)) { - return 1; - } else { - return 0; - } - } else { - return 1; - } - } else if (b) { - return -1; - } else { - return 0; - } + if (a) { + if (b) { + if (*reinterpret_cast(a) < *reinterpret_cast(b)) { + return -1; + } + else if ( + *reinterpret_cast(b) < *reinterpret_cast(a)) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } + } + else if (b) { + return -1; + } + else { + return 0; + } } -ZT_MAYBE_UNUSED void ZT_Identity_delete(const ZT_Identity *id) +ZT_MAYBE_UNUSED void ZT_Identity_delete(const ZT_Identity* id) { - if (id) - delete reinterpret_cast(id); + if (id) + delete reinterpret_cast(id); } /********************************************************************************************************************/ ZT_MAYBE_UNUSED int ZT_Certificate_newKeyPair( - const enum ZT_CertificatePublicKeyAlgorithm type, - uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], - int *const publicKeySize, - uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], - int *const privateKeySize) + const enum ZT_CertificatePublicKeyAlgorithm type, + uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], + int* const publicKeySize, + uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], + int* const privateKeySize) { - try { - return ZeroTier::Certificate::newKeyPair(type, publicKey, publicKeySize, privateKey, privateKeySize) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return ZeroTier::Certificate::newKeyPair(type, publicKey, publicKeySize, privateKey, privateKeySize) + ? ZT_RESULT_OK + : ZT_RESULT_ERROR_BAD_PARAMETER; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } ZT_MAYBE_UNUSED int ZT_Certificate_newCSR( - const ZT_Certificate_Subject *subject, - const void *const certificatePublicKey, - const int certificatePublicKeySize, - const void *const uniqueIdPrivateKey, - const int uniqueIdPrivateKeySize, - void *const csr, - int *const csrSize) + const ZT_Certificate_Subject* subject, + const void* const certificatePublicKey, + const int certificatePublicKeySize, + const void* const uniqueIdPrivateKey, + const int uniqueIdPrivateKeySize, + void* const csr, + int* const csrSize) { - try { - if ((!subject) || (!certificatePublicKey) || (certificatePublicKeySize <= 0) || (certificatePublicKeySize > ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) - return ZT_RESULT_ERROR_BAD_PARAMETER; - const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, certificatePublicKey, (unsigned int)certificatePublicKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize)); - if (csrV.empty() || ((int)csrV.size() > *csrSize)) - return ZT_RESULT_ERROR_BAD_PARAMETER; - ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size()); - *csrSize = (int)csrV.size(); - return ZT_RESULT_OK; - } catch (...) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + if ((! subject) || (! certificatePublicKey) || (certificatePublicKeySize <= 0) + || (certificatePublicKeySize > ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) + return ZT_RESULT_ERROR_BAD_PARAMETER; + const ZeroTier::Vector csrV(ZeroTier::Certificate::createCSR( + *subject, + certificatePublicKey, + (unsigned int)certificatePublicKeySize, + uniqueIdPrivateKey, + (unsigned int)uniqueIdPrivateKeySize)); + if (csrV.empty() || ((int)csrV.size() > *csrSize)) + return ZT_RESULT_ERROR_BAD_PARAMETER; + ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size()); + *csrSize = (int)csrV.size(); + return ZT_RESULT_OK; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED ZT_Certificate *ZT_Certificate_sign( - const ZT_Certificate *cert, - const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], - const void *issuerPrivateKey, - int issuerPrivateKeySize) +ZT_MAYBE_UNUSED ZT_Certificate* ZT_Certificate_sign( + const ZT_Certificate* cert, + const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], + const void* issuerPrivateKey, + int issuerPrivateKeySize) { - try { - ZeroTier::Certificate *const c = new ZeroTier::Certificate(*cert); - if (c->sign(issuer, issuerPrivateKey, issuerPrivateKeySize)) { - return c; - } else { - delete c; - } - } catch (...) {} - return nullptr; + try { + ZeroTier::Certificate* const c = new ZeroTier::Certificate(*cert); + if (c->sign(issuer, issuerPrivateKey, issuerPrivateKeySize)) { + return c; + } + else { + delete c; + } + } + catch (...) { + } + return nullptr; } -ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_decode( - const ZT_Certificate **decodedCert, - const void *cert, - int certSize, - int verify) +ZT_MAYBE_UNUSED enum ZT_CertificateError +ZT_Certificate_decode(const ZT_Certificate** decodedCert, const void* cert, int certSize, int verify) { - try { - if ((!decodedCert) || (!cert) || (certSize <= 0)) - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - *decodedCert = nullptr; - ZeroTier::Certificate *const c = new ZeroTier::Certificate(); - if (!c->decode(cert, certSize)) { - delete c; - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } - if (verify) { - const ZT_CertificateError err = c->verify(-1, true); - if (err != ZT_CERTIFICATE_ERROR_NONE) { - delete c; - return err; - } - } - *decodedCert = c; - return ZT_CERTIFICATE_ERROR_NONE; - } catch (...) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + try { + if ((! decodedCert) || (! cert) || (certSize <= 0)) + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + *decodedCert = nullptr; + ZeroTier::Certificate* const c = new ZeroTier::Certificate(); + if (! c->decode(cert, certSize)) { + delete c; + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } + if (verify) { + const ZT_CertificateError err = c->verify(-1, true); + if (err != ZT_CERTIFICATE_ERROR_NONE) { + delete c; + return err; + } + } + *decodedCert = c; + return ZT_CERTIFICATE_ERROR_NONE; + } + catch (...) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } } -ZT_MAYBE_UNUSED int ZT_Certificate_encode( - const ZT_Certificate *cert, - void *encoded, - int *encodedSize) +ZT_MAYBE_UNUSED int ZT_Certificate_encode(const ZT_Certificate* cert, void* encoded, int* encodedSize) { - try { - if ((!cert) || (!encoded) || (!encodedSize)) - return ZT_RESULT_ERROR_BAD_PARAMETER; - ZeroTier::Certificate c(*cert); - ZeroTier::Vector< uint8_t > enc(c.encode()); - if ((int)enc.size() > *encodedSize) - return ZT_RESULT_ERROR_BAD_PARAMETER; - ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size()); - *encodedSize = (int)enc.size(); - return ZT_RESULT_OK; - } catch (...) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + if ((! cert) || (! encoded) || (! encodedSize)) + return ZT_RESULT_ERROR_BAD_PARAMETER; + ZeroTier::Certificate c(*cert); + ZeroTier::Vector enc(c.encode()); + if ((int)enc.size() > *encodedSize) + return ZT_RESULT_ERROR_BAD_PARAMETER; + ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size()); + *encodedSize = (int)enc.size(); + return ZT_RESULT_OK; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_verify( - const ZT_Certificate *cert, - int64_t clock) +ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate* cert, int64_t clock) { - try { - if (!cert) - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - return ZeroTier::Certificate(*cert).verify(clock, true); - } catch (...) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + try { + if (! cert) + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + return ZeroTier::Certificate(*cert).verify(clock, true); + } + catch (...) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } } -ZT_MAYBE_UNUSED const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert) +ZT_MAYBE_UNUSED const ZT_Certificate* ZT_Certificate_clone(const ZT_Certificate* cert) { - try { - if (!cert) - return nullptr; - return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert)); - } catch (...) { - return nullptr; - } + try { + if (! cert) + return nullptr; + return (const ZT_Certificate*)(new ZeroTier::Certificate(*cert)); + } + catch (...) { + return nullptr; + } } -ZT_MAYBE_UNUSED void ZT_Certificate_delete(const ZT_Certificate *cert) +ZT_MAYBE_UNUSED void ZT_Certificate_delete(const ZT_Certificate* cert) { - try { - if (cert) - delete (const ZeroTier::Certificate *)(cert); - } catch (...) {} + try { + if (cert) + delete (const ZeroTier::Certificate*)(cert); + } + catch (...) { + } } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED char *ZT_Endpoint_toString( - const ZT_Endpoint *ep, - char *buf, - int capacity) +ZT_MAYBE_UNUSED char* ZT_Endpoint_toString(const ZT_Endpoint* ep, char* buf, int capacity) { - if ((!ep) || (!buf) || (capacity < ZT_ENDPOINT_STRING_SIZE_MAX)) - return nullptr; - return reinterpret_cast(ep)->toString(buf); + if ((! ep) || (! buf) || (capacity < ZT_ENDPOINT_STRING_SIZE_MAX)) + return nullptr; + return reinterpret_cast(ep)->toString(buf); } -ZT_MAYBE_UNUSED int ZT_Endpoint_fromString( - ZT_Endpoint *ep, - const char *str) +ZT_MAYBE_UNUSED int ZT_Endpoint_fromString(ZT_Endpoint* ep, const char* str) { - if ((!ep) || (!str)) - return ZT_RESULT_ERROR_BAD_PARAMETER; - return reinterpret_cast(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER; + if ((! ep) || (! str)) + return ZT_RESULT_ERROR_BAD_PARAMETER; + return reinterpret_cast(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER; } -ZT_MAYBE_UNUSED int ZT_Endpoint_fromBytes( - ZT_Endpoint *ep, - const void *bytes, - unsigned int len) +ZT_MAYBE_UNUSED int ZT_Endpoint_fromBytes(ZT_Endpoint* ep, const void* bytes, unsigned int len) { - if ((!ep) || (!bytes) || (!len)) - return ZT_RESULT_ERROR_BAD_PARAMETER; - return (reinterpret_cast(ep)->unmarshal(reinterpret_cast(bytes), (int)len) > 0) ? 0 : ZT_RESULT_ERROR_BAD_PARAMETER; + if ((! ep) || (! bytes) || (! len)) + return ZT_RESULT_ERROR_BAD_PARAMETER; + return (reinterpret_cast(ep)->unmarshal(reinterpret_cast(bytes), (int)len) > 0) + ? 0 + : ZT_RESULT_ERROR_BAD_PARAMETER; } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED char *ZT_Fingerprint_toString(const ZT_Fingerprint *fp, char *buf, int capacity) +ZT_MAYBE_UNUSED char* ZT_Fingerprint_toString(const ZT_Fingerprint* fp, char* buf, int capacity) { - if (capacity < ZT_FINGERPRINT_STRING_SIZE_MAX) - return nullptr; - return reinterpret_cast(fp)->toString(buf); + if (capacity < ZT_FINGERPRINT_STRING_SIZE_MAX) + return nullptr; + return reinterpret_cast(fp)->toString(buf); } -ZT_MAYBE_UNUSED int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s) +ZT_MAYBE_UNUSED int ZT_Fingerprint_fromString(ZT_Fingerprint* fp, const char* s) { - if ((!fp)||(!s)) - return 0; - ZeroTier::Fingerprint f; - if (f.fromString(s)) { - *fp = f; - return 1; - } - return 0; + if ((! fp) || (! s)) + return 0; + ZeroTier::Fingerprint f; + if (f.fromString(s)) { + *fp = f; + return 1; + } + return 0; } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED void ZT_InetAddress_clear(ZT_InetAddress *ia) +ZT_MAYBE_UNUSED void ZT_InetAddress_clear(ZT_InetAddress* ia) { - if (likely(ia != nullptr)) - ZeroTier::Utils::zero(ia); + if (likely(ia != nullptr)) + ZeroTier::Utils::zero(ia); } -ZT_MAYBE_UNUSED char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, unsigned int cap) +ZT_MAYBE_UNUSED char* ZT_InetAddress_toString(const ZT_InetAddress* ia, char* buf, unsigned int cap) { - if (likely((cap > 0)&&(buf != nullptr))) { - if (likely((ia != nullptr)&&(cap >= ZT_INETADDRESS_STRING_SIZE_MAX))) { - reinterpret_cast(ia)->toString(buf); - } else { - buf[0] = 0; - } - } - return buf; + if (likely((cap > 0) && (buf != nullptr))) { + if (likely((ia != nullptr) && (cap >= ZT_INETADDRESS_STRING_SIZE_MAX))) { + reinterpret_cast(ia)->toString(buf); + } + else { + buf[0] = 0; + } + } + return buf; } -ZT_MAYBE_UNUSED int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str) +ZT_MAYBE_UNUSED int ZT_InetAddress_fromString(ZT_InetAddress* ia, const char* str) { - if (likely((ia != nullptr)&&(str != nullptr))) { - return (int)reinterpret_cast(ia)->fromString(str); - } - return 0; + if (likely((ia != nullptr) && (str != nullptr))) { + return (int)reinterpret_cast(ia)->fromString(str); + } + return 0; } -ZT_MAYBE_UNUSED void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr) +ZT_MAYBE_UNUSED void ZT_InetAddress_set(ZT_InetAddress* ia, const void* saddr) { - if (likely(ia != nullptr)) - (*reinterpret_cast(ia)) = reinterpret_cast(saddr); + if (likely(ia != nullptr)) + (*reinterpret_cast(ia)) = reinterpret_cast(saddr); } -ZT_MAYBE_UNUSED void ZT_InetAddress_setIpBytes(ZT_InetAddress *ia, const void *ipBytes, unsigned int ipLen, unsigned int port) +ZT_MAYBE_UNUSED void +ZT_InetAddress_setIpBytes(ZT_InetAddress* ia, const void* ipBytes, unsigned int ipLen, unsigned int port) { - if (likely(ia != nullptr)) - reinterpret_cast(ia)->set(ipBytes, ipLen, port); + if (likely(ia != nullptr)) + reinterpret_cast(ia)->set(ipBytes, ipLen, port); } -ZT_MAYBE_UNUSED void ZT_InetAddress_setPort(ZT_InetAddress *ia, unsigned int port) +ZT_MAYBE_UNUSED void ZT_InetAddress_setPort(ZT_InetAddress* ia, unsigned int port) { - if (likely(ia != nullptr)) - reinterpret_cast(ia)->setPort(port); + if (likely(ia != nullptr)) + reinterpret_cast(ia)->setPort(port); } -ZT_MAYBE_UNUSED unsigned int ZT_InetAddress_port(const ZT_InetAddress *ia) +ZT_MAYBE_UNUSED unsigned int ZT_InetAddress_port(const ZT_InetAddress* ia) { - if (likely(ia != nullptr)) - return reinterpret_cast(ia)->port(); - return 0; + if (likely(ia != nullptr)) + return reinterpret_cast(ia)->port(); + return 0; } -ZT_MAYBE_UNUSED int ZT_InetAddress_isNil(const ZT_InetAddress *ia) +ZT_MAYBE_UNUSED int ZT_InetAddress_isNil(const ZT_InetAddress* ia) { - if (!ia) - return 0; - return (int)((bool)(*reinterpret_cast(ia))); + if (! ia) + return 0; + return (int)((bool)(*reinterpret_cast(ia))); } -ZT_MAYBE_UNUSED int ZT_InetAddress_isV4(const ZT_InetAddress *ia) +ZT_MAYBE_UNUSED int ZT_InetAddress_isV4(const ZT_InetAddress* ia) { - if (!ia) - return 0; - return (int)(reinterpret_cast(ia))->isV4(); + if (! ia) + return 0; + return (int)(reinterpret_cast(ia))->isV4(); } -ZT_MAYBE_UNUSED int ZT_InetAddress_isV6(const ZT_InetAddress *ia) +ZT_MAYBE_UNUSED int ZT_InetAddress_isV6(const ZT_InetAddress* ia) { - if (!ia) - return 0; - return (int)(reinterpret_cast(ia))->isV6(); + if (! ia) + return 0; + return (int)(reinterpret_cast(ia))->isV6(); } -ZT_MAYBE_UNUSED unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress *ia, void *buf) +ZT_MAYBE_UNUSED unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress* ia, void* buf) { - if (ia) { - switch(reinterpret_cast(ia)->as.sa.sa_family) { - case AF_INET: - ZeroTier::Utils::copy<4>(buf, &(reinterpret_cast(ia)->as.sa_in.sin_addr.s_addr)); - return 4; - case AF_INET6: - ZeroTier::Utils::copy<16>(buf, reinterpret_cast(ia)->as.sa_in6.sin6_addr.s6_addr); - return 16; - } - } - return 0; + if (ia) { + switch (reinterpret_cast(ia)->as.sa.sa_family) { + case AF_INET: + ZeroTier::Utils::copy<4>( + buf, + &(reinterpret_cast(ia)->as.sa_in.sin_addr.s_addr)); + return 4; + case AF_INET6: + ZeroTier::Utils::copy<16>( + buf, + reinterpret_cast(ia)->as.sa_in6.sin6_addr.s6_addr); + return 16; + } + } + return 0; } -ZT_MAYBE_UNUSED enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia) +ZT_MAYBE_UNUSED enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress* ia) { - if (likely(ia != nullptr)) - return reinterpret_cast(ia)->ipScope(); - return ZT_IP_SCOPE_NONE; + if (likely(ia != nullptr)) + return reinterpret_cast(ia)->ipScope(); + return ZT_IP_SCOPE_NONE; } -ZT_MAYBE_UNUSED int ZT_InetAddress_compare(const ZT_InetAddress *a, const ZT_InetAddress *b) +ZT_MAYBE_UNUSED int ZT_InetAddress_compare(const ZT_InetAddress* a, const ZT_InetAddress* b) { - if (a) { - if (b) { - if (*reinterpret_cast(a) < *reinterpret_cast(b)) { - return -1; - } else if (*reinterpret_cast(b) < *reinterpret_cast(a)) { - return 1; - } else { - return 0; - } - } else { - return 1; - } - } else if (b) { - return -1; - } else { - return 0; - } + if (a) { + if (b) { + if (*reinterpret_cast(a) + < *reinterpret_cast(b)) { + return -1; + } + else if ( + *reinterpret_cast(b) + < *reinterpret_cast(a)) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } + } + else if (b) { + return -1; + } + else { + return 0; + } } /********************************************************************************************************************/ -ZT_MAYBE_UNUSED int ZT_Dictionary_parse(const void *const dict, const unsigned int len, void *const arg, void (*f)(void *, const char *, unsigned int, const void *, unsigned int)) +ZT_MAYBE_UNUSED int ZT_Dictionary_parse( + const void* const dict, + const unsigned int len, + void* const arg, + void (*f)(void*, const char*, unsigned int, const void*, unsigned int)) { - ZeroTier::Dictionary d; - if (d.decode(dict, len)) { - for(ZeroTier::Dictionary::const_iterator i(d.begin());i!=d.end();++i) { - f(arg, i->first.c_str(), (unsigned int)i->first.length(), i->second.data(), (unsigned int)i->second.size()); - } - return 1; - } - return 0; + ZeroTier::Dictionary d; + if (d.decode(dict, len)) { + for (ZeroTier::Dictionary::const_iterator i(d.begin()); i != d.end(); ++i) { + f(arg, i->first.c_str(), (unsigned int)i->first.length(), i->second.data(), (unsigned int)i->second.size()); + } + return 1; + } + return 0; } /********************************************************************************************************************/ ZT_MAYBE_UNUSED uint64_t ZT_random() -{ return ZeroTier::Utils::random(); } +{ + return ZeroTier::Utils::random(); +} -} // extern "C" +} // extern "C" diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 4f668d320..e0786f202 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required(VERSION 3.0) project(zt_core) configure_file( @@ -61,7 +61,7 @@ set(core_headers Utils.hpp VL1.hpp VL2.hpp -) + ) set(core_src AES.cpp @@ -102,22 +102,22 @@ set(core_src Utils.cpp VL1.cpp VL2.cpp -) + ) add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers}) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) -if(WIN32) +if (WIN32) set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) -else(WIN32) +else (WIN32) set(libs ${libs} pthread) if (APPLE) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) - else(APPLE) + else (APPLE) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) - endif(APPLE) -endif(WIN32) + endif (APPLE) +endif (WIN32) add_executable(zt_core_tests Tests.h Tests.cpp) target_compile_definitions(zt_core_tests PRIVATE ZT_ENABLE_TESTS=1 ZT_STANDALONE_TESTS=1) diff --git a/core/CallContext.hpp b/core/CallContext.hpp index 41f841456..189edb04c 100644 --- a/core/CallContext.hpp +++ b/core/CallContext.hpp @@ -25,40 +25,37 @@ namespace ZeroTier { * graph around from function to function as needed. It's cleaner and probably * faster than passing clock, ticks, and tPtr around everywhere. */ -class CallContext -{ -public: - ZT_INLINE CallContext(const int64_t c, const int64_t t, void *const p) : - clock(c), - ticks(t), - tPtr(p) - {} +class CallContext { + public: + ZT_INLINE CallContext(const int64_t c, const int64_t t, void* const p) : clock(c), ticks(t), tPtr(p) + { + } - /** - * Real world time in milliseconds since Unix epoch or -1 if unknown. - * - * This is used for things like checking certificate expiration. If it's - * not known then the value may be inferred from peers/roots or some - * features may be disabled. - */ - const int64_t clock; + /** + * Real world time in milliseconds since Unix epoch or -1 if unknown. + * + * This is used for things like checking certificate expiration. If it's + * not known then the value may be inferred from peers/roots or some + * features may be disabled. + */ + const int64_t clock; - /** - * Monotonic process or system clock in milliseconds since an arbitrary point. - * - * This is never -1 or undefined and is used for most timings. - */ - const int64_t ticks; + /** + * Monotonic process or system clock in milliseconds since an arbitrary point. + * + * This is never -1 or undefined and is used for most timings. + */ + const int64_t ticks; - /** - * An arbitrary pointer users pass into calls that follows the call chain - * - * By passing this back to callbacks state can be kept by the caller using - * a mechanism that is faster (on most platforms) than thread-local storage. - */ - void *const tPtr; + /** + * An arbitrary pointer users pass into calls that follows the call chain + * + * By passing this back to callbacks state can be kept by the caller using + * a mechanism that is faster (on most platforms) than thread-local storage. + */ + void* const tPtr; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/CapabilityCredential.cpp b/core/CapabilityCredential.cpp index 2b855120f..d144107bb 100644 --- a/core/CapabilityCredential.cpp +++ b/core/CapabilityCredential.cpp @@ -12,421 +12,451 @@ /****/ #include "CapabilityCredential.hpp" -#include "Utils.hpp" + #include "Constants.hpp" #include "MAC.hpp" +#include "Utils.hpp" namespace ZeroTier { CapabilityCredential::CapabilityCredential( - const uint32_t id, - const uint64_t nwid, - const int64_t timestamp, - const ZT_VirtualNetworkRule *const rules, - const unsigned int ruleCount) noexcept: - m_nwid(nwid), - m_timestamp(timestamp), - m_id(id), - m_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES), - m_signatureLength(0) + const uint32_t id, + const uint64_t nwid, + const int64_t timestamp, + const ZT_VirtualNetworkRule* const rules, + const unsigned int ruleCount) noexcept + : m_nwid(nwid) + , m_timestamp(timestamp) + , m_id(id) + , m_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES) + , m_signatureLength(0) { - Utils::zero< sizeof(m_rules) >(m_rules); - if (m_ruleCount > 0) - Utils::copy(m_rules, rules, sizeof(ZT_VirtualNetworkRule) * m_ruleCount); - Utils::zero< sizeof(m_signature) >(m_signature); + Utils::zero(m_rules); + if (m_ruleCount > 0) + Utils::copy(m_rules, rules, sizeof(ZT_VirtualNetworkRule) * m_ruleCount); + Utils::zero(m_signature); } -bool CapabilityCredential::sign(const Identity &from, const Address &to) noexcept +bool CapabilityCredential::sign(const Identity& from, const Address& to) noexcept { - uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16]; - m_issuedTo = to; - m_signedBy = from.address(); - m_signatureLength = from.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature)); - return m_signatureLength > 0; + uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16]; + m_issuedTo = to; + m_signedBy = from.address(); + m_signatureLength = from.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); + return m_signatureLength > 0; } int CapabilityCredential::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool forSign) const noexcept { - int p = 0; + int p = 0; - if (forSign) { - for (int k = 0;k < 8;++k) - data[p++] = 0x7f; - } + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } - Utils::storeBigEndian(data + p, m_nwid); - Utils::storeBigEndian(data + p + 8, (uint64_t) m_timestamp); - Utils::storeBigEndian(data + p + 16, m_id); - p += 20; + Utils::storeBigEndian(data + p, m_nwid); + Utils::storeBigEndian(data + p + 8, (uint64_t)m_timestamp); + Utils::storeBigEndian(data + p + 16, m_id); + p += 20; - Utils::storeBigEndian(data + p, (uint16_t) m_ruleCount); - p += 2; - p += CapabilityCredential::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount); + Utils::storeBigEndian(data + p, (uint16_t)m_ruleCount); + p += 2; + p += CapabilityCredential::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount); - // LEGACY: older versions supported multiple records with this being a maximum custody - // chain length. This is deprecated so set the max chain length to one. - data[p++] = (uint8_t)1; + // LEGACY: older versions supported multiple records with this being a maximum custody + // chain length. This is deprecated so set the max chain length to one. + data[p++] = (uint8_t)1; - if (!forSign) { - m_issuedTo.copyTo(data + p); - m_signedBy.copyTo(data + p + ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH; - data[p++] = 1; // LEGACY: old versions require a reserved byte here - Utils::storeBigEndian(data + p, (uint16_t) m_signatureLength); - p += 2; - Utils::copy(data + p, m_signature, m_signatureLength); - p += (int)m_signatureLength; + if (! forSign) { + m_issuedTo.copyTo(data + p); + m_signedBy.copyTo(data + p + ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH; + data[p++] = 1; // LEGACY: old versions require a reserved byte here + Utils::storeBigEndian(data + p, (uint16_t)m_signatureLength); + p += 2; + Utils::copy(data + p, m_signature, m_signatureLength); + p += (int)m_signatureLength; - // LEGACY: older versions supported more than one record terminated by a zero address. - for (int k = 0;k < ZT_ADDRESS_LENGTH;++k) - data[p++] = 0; - } + // LEGACY: older versions supported more than one record terminated by a zero address. + for (int k = 0; k < ZT_ADDRESS_LENGTH; ++k) + data[p++] = 0; + } - data[p++] = 0; - data[p++] = 0; // uint16_t size of additional fields, currently 0 + data[p++] = 0; + data[p++] = 0; // uint16_t size of additional fields, currently 0 - if (forSign) { - for (int k = 0;k < 8;++k) - data[p++] = 0x7f; - } + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } - return p; + return p; } -int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept +int CapabilityCredential::unmarshal(const uint8_t* data, int len) noexcept { - if (len < 22) - return -1; + if (len < 22) + return -1; - m_nwid = Utils::loadBigEndian(data); - m_timestamp = (int64_t) Utils::loadBigEndian(data + 8); - m_id = Utils::loadBigEndian(data + 16); + m_nwid = Utils::loadBigEndian(data); + m_timestamp = (int64_t)Utils::loadBigEndian(data + 8); + m_id = Utils::loadBigEndian(data + 16); - const unsigned int rc = Utils::loadBigEndian(data + 20); - if (rc > ZT_MAX_CAPABILITY_RULES) - return -1; - const int rulesLen = unmarshalVirtualNetworkRules(data + 22, len - 22, m_rules, m_ruleCount, rc); - if (rulesLen < 0) - return rulesLen; - int p = 22 + rulesLen; + const unsigned int rc = Utils::loadBigEndian(data + 20); + if (rc > ZT_MAX_CAPABILITY_RULES) + return -1; + const int rulesLen = unmarshalVirtualNetworkRules(data + 22, len - 22, m_rules, m_ruleCount, rc); + if (rulesLen < 0) + return rulesLen; + int p = 22 + rulesLen; - if (p >= len) - return -1; - ++p; // LEGACY: skip old max record count + if (p >= len) + return -1; + ++p; // LEGACY: skip old max record count - // LEGACY: since it was once supported to have multiple records, scan them all. Since - // this feature was never used, just set the signature and issued to and other related - // fields each time and we should only ever see one. If there's more than one and the - // last is not the controller, this credential will just fail validity check. - for (unsigned int i = 0;;++i) { - if ((p + ZT_ADDRESS_LENGTH) > len) - return -1; - const Address to(data + p); - p += ZT_ADDRESS_LENGTH; + // LEGACY: since it was once supported to have multiple records, scan them all. Since + // this feature was never used, just set the signature and issued to and other related + // fields each time and we should only ever see one. If there's more than one and the + // last is not the controller, this credential will just fail validity check. + for (unsigned int i = 0;; ++i) { + if ((p + ZT_ADDRESS_LENGTH) > len) + return -1; + const Address to(data + p); + p += ZT_ADDRESS_LENGTH; - if (!to) - break; + if (! to) + break; - m_issuedTo = to; - if ((p + ZT_ADDRESS_LENGTH) > len) - return -1; - m_signedBy.setTo(data + p); - p += ZT_ADDRESS_LENGTH + 1; // LEGACY: +1 to skip reserved field + m_issuedTo = to; + if ((p + ZT_ADDRESS_LENGTH) > len) + return -1; + m_signedBy.setTo(data + p); + p += ZT_ADDRESS_LENGTH + 1; // LEGACY: +1 to skip reserved field - if ((p + 2) > len) - return -1; - m_signatureLength = Utils::loadBigEndian(data + p); - p += 2; - if ((m_signatureLength > sizeof(m_signature)) || ((p + (int) m_signatureLength) > len)) - return -1; - Utils::copy(m_signature, data + p, m_signatureLength); - p += (int) m_signatureLength; - } + if ((p + 2) > len) + return -1; + m_signatureLength = Utils::loadBigEndian(data + p); + p += 2; + if ((m_signatureLength > sizeof(m_signature)) || ((p + (int)m_signatureLength) > len)) + return -1; + Utils::copy(m_signature, data + p, m_signatureLength); + p += (int)m_signatureLength; + } - if ((p + 2) > len) - return -1; - p += 2 + Utils::loadBigEndian(data + p); + if ((p + 2) > len) + return -1; + p += 2 + Utils::loadBigEndian(data + p); - if (p > len) - return -1; + if (p > len) + return -1; - return p; + return p; } -int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *const rules, const unsigned int ruleCount) noexcept +int CapabilityCredential::marshalVirtualNetworkRules( + uint8_t* data, + const ZT_VirtualNetworkRule* const rules, + const unsigned int ruleCount) noexcept { - int p = 0; - for (unsigned int i = 0;i < ruleCount;++i) { - data[p++] = rules[i].t; - switch ((ZT_VirtualNetworkRuleType) (rules[i].t & 0x3fU)) { - default: - data[p++] = 0; - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - data[p++] = 14; - Utils::storeBigEndian(data + p, rules[i].v.fwd.address); - p += 8; - Utils::storeBigEndian(data + p, rules[i].v.fwd.flags); - p += 4; - Utils::storeBigEndian(data + p, rules[i].v.fwd.length); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - data[p++] = 5; - Address(rules[i].v.zt).copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - data[p++] = 2; - Utils::storeBigEndian(data + p, rules[i].v.vlanId); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - data[p++] = 1; - data[p++] = rules[i].v.vlanPcp; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - data[p++] = 1; - data[p++] = rules[i].v.vlanDei; - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - data[p++] = 6; - MAC(rules[i].v.mac).copyTo(data + p); - p += 6; - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - data[p++] = 5; - data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[0]; - data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[1]; - data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[2]; - data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[3]; - data[p++] = rules[i].v.ipv4.mask; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - data[p++] = 17; - Utils::copy<16>(data + p, rules[i].v.ipv6.ip); - p += 16; - data[p++] = rules[i].v.ipv6.mask; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - data[p++] = 3; - data[p++] = rules[i].v.ipTos.mask; - data[p++] = rules[i].v.ipTos.value[0]; - data[p++] = rules[i].v.ipTos.value[1]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - data[p++] = 1; - data[p++] = rules[i].v.ipProtocol; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - data[p++] = 2; - Utils::storeBigEndian(data + p, rules[i].v.etherType); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - data[p++] = 3; - data[p++] = rules[i].v.icmp.type; - data[p++] = rules[i].v.icmp.code; - data[p++] = rules[i].v.icmp.flags; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - data[p++] = 4; - Utils::storeBigEndian(data + p, rules[i].v.port[0]); - p += 2; - Utils::storeBigEndian(data + p, rules[i].v.port[1]); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - data[p++] = 8; - Utils::storeBigEndian(data + p, rules[i].v.characteristics); - p += 8; - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - data[p++] = 4; - Utils::storeBigEndian(data + p, rules[i].v.frameSize[0]); - p += 2; - Utils::storeBigEndian(data + p, rules[i].v.frameSize[1]); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - data[p++] = 4; - Utils::storeBigEndian(data + p, rules[i].v.randomProbability); - p += 4; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: - data[p++] = 8; - Utils::storeBigEndian(data + p, rules[i].v.tag.id); - p += 4; - Utils::storeBigEndian(data + p, rules[i].v.tag.value); - p += 4; - break; - case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: - data[p++] = 19; - Utils::storeBigEndian(data + p, rules[i].v.intRange.start); - p += 8; - Utils::storeBigEndian(data + p, rules[i].v.intRange.start + (uint64_t) rules[i].v.intRange.end); - p += 8; - Utils::storeBigEndian(data + p, rules[i].v.intRange.idx); - p += 2; - data[p++] = rules[i].v.intRange.format; - break; - } - } - return p; + int p = 0; + for (unsigned int i = 0; i < ruleCount; ++i) { + data[p++] = rules[i].t; + switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3fU)) { + default: + data[p++] = 0; + break; + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + data[p++] = 14; + Utils::storeBigEndian(data + p, rules[i].v.fwd.address); + p += 8; + Utils::storeBigEndian(data + p, rules[i].v.fwd.flags); + p += 4; + Utils::storeBigEndian(data + p, rules[i].v.fwd.length); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + data[p++] = 5; + Address(rules[i].v.zt).copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + data[p++] = 2; + Utils::storeBigEndian(data + p, rules[i].v.vlanId); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + data[p++] = 1; + data[p++] = rules[i].v.vlanPcp; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + data[p++] = 1; + data[p++] = rules[i].v.vlanDei; + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + data[p++] = 6; + MAC(rules[i].v.mac).copyTo(data + p); + p += 6; + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + data[p++] = 5; + data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[0]; + data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[1]; + data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[2]; + data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[3]; + data[p++] = rules[i].v.ipv4.mask; + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + data[p++] = 17; + Utils::copy<16>(data + p, rules[i].v.ipv6.ip); + p += 16; + data[p++] = rules[i].v.ipv6.mask; + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + data[p++] = 3; + data[p++] = rules[i].v.ipTos.mask; + data[p++] = rules[i].v.ipTos.value[0]; + data[p++] = rules[i].v.ipTos.value[1]; + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + data[p++] = 1; + data[p++] = rules[i].v.ipProtocol; + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + data[p++] = 2; + Utils::storeBigEndian(data + p, rules[i].v.etherType); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + data[p++] = 3; + data[p++] = rules[i].v.icmp.type; + data[p++] = rules[i].v.icmp.code; + data[p++] = rules[i].v.icmp.flags; + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + data[p++] = 4; + Utils::storeBigEndian(data + p, rules[i].v.port[0]); + p += 2; + Utils::storeBigEndian(data + p, rules[i].v.port[1]); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: + data[p++] = 8; + Utils::storeBigEndian(data + p, rules[i].v.characteristics); + p += 8; + break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + data[p++] = 4; + Utils::storeBigEndian(data + p, rules[i].v.frameSize[0]); + p += 2; + Utils::storeBigEndian(data + p, rules[i].v.frameSize[1]); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + data[p++] = 4; + Utils::storeBigEndian(data + p, rules[i].v.randomProbability); + p += 4; + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: + data[p++] = 8; + Utils::storeBigEndian(data + p, rules[i].v.tag.id); + p += 4; + Utils::storeBigEndian(data + p, rules[i].v.tag.value); + p += 4; + break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: + data[p++] = 19; + Utils::storeBigEndian(data + p, rules[i].v.intRange.start); + p += 8; + Utils::storeBigEndian( + data + p, + rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end); + p += 8; + Utils::storeBigEndian(data + p, rules[i].v.intRange.idx); + p += 2; + data[p++] = rules[i].v.intRange.format; + break; + } + } + return p; } -int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data, const int len, ZT_VirtualNetworkRule *const rules, unsigned int &ruleCount, const unsigned int maxRuleCount) noexcept +int CapabilityCredential::unmarshalVirtualNetworkRules( + const uint8_t* const data, + const int len, + ZT_VirtualNetworkRule* const rules, + unsigned int& ruleCount, + const unsigned int maxRuleCount) noexcept { - int p = 0; - unsigned int rc = 0; - while (rc < maxRuleCount) { - if (p >= len) - return -1; - rules[ruleCount].t = data[p++]; - const int fieldLen = (int) data[p++]; - if ((p + fieldLen) > len) - return -1; - switch ((ZT_VirtualNetworkRuleType) (rules[ruleCount].t & 0x3fU)) { - default: - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - if ((p + 14) > len) return -1; - rules[ruleCount].v.fwd.address = Utils::loadBigEndian(data + p); - p += 8; - rules[ruleCount].v.fwd.flags = Utils::loadBigEndian(data + p); - p += 4; - rules[ruleCount].v.fwd.length = Utils::loadBigEndian(data + p); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - if ((p + ZT_ADDRESS_LENGTH) > len) return -1; - rules[ruleCount].v.zt = Address(data + p).toInt(); - p += ZT_ADDRESS_LENGTH; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - if ((p + 2) > len) return -1; - rules[ruleCount].v.vlanId = Utils::loadBigEndian(data + p); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - if ((p + 1) > len) return -1; - rules[ruleCount].v.vlanPcp = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - if ((p + 1) > len) return -1; - rules[ruleCount].v.vlanDei = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - if ((p + 6) > len) return -1; - Utils::copy<6>(rules[ruleCount].v.mac, data + p); - p += 6; - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - if ((p + 5) > len) return -1; - Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip), data + p); - p += 4; - rules[ruleCount].v.ipv4.mask = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - if ((p + 17) > len) return -1; - Utils::copy<16>(rules[ruleCount].v.ipv6.ip, data + p); - p += 16; - rules[ruleCount].v.ipv6.mask = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - if ((p + 3) > len) return -1; - rules[ruleCount].v.ipTos.mask = data[p++]; - rules[ruleCount].v.ipTos.value[0] = data[p++]; - rules[ruleCount].v.ipTos.value[1] = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - if ((p + 1) > len) return -1; - rules[ruleCount].v.ipProtocol = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - if ((p + 2) > len) return -1; - rules[ruleCount].v.etherType = Utils::loadBigEndian(data + p); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - if ((p + 3) > len) return -1; - rules[ruleCount].v.icmp.type = data[p++]; - rules[ruleCount].v.icmp.code = data[p++]; - rules[ruleCount].v.icmp.flags = data[p++]; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - if ((p + 4) > len) return -1; - rules[ruleCount].v.port[0] = Utils::loadBigEndian(data + p); - p += 2; - rules[ruleCount].v.port[1] = Utils::loadBigEndian(data + p); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - if ((p + 8) > len) return -1; - rules[ruleCount].v.characteristics = Utils::loadBigEndian(data + p); - p += 8; - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - if ((p + 4) > len) return -1; - rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian(data + p); - p += 2; - rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian(data + p); - p += 2; - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - if ((p + 4) > len) return -1; - rules[ruleCount].v.randomProbability = Utils::loadBigEndian(data + p); - p += 4; - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: - if ((p + 4) > len) return -1; - rules[ruleCount].v.tag.id = Utils::loadBigEndian(data + p); - p += 4; - rules[ruleCount].v.tag.value = Utils::loadBigEndian(data + p); - p += 4; - break; - case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: - if ((p + 19) > len) return -1; - rules[ruleCount].v.intRange.start = Utils::loadBigEndian(data + p); - p += 8; - rules[ruleCount].v.intRange.end = (uint32_t) (Utils::loadBigEndian(data + p) - rules[ruleCount].v.intRange.start); - p += 8; - rules[ruleCount].v.intRange.idx = Utils::loadBigEndian(data + p); - p += 2; - rules[ruleCount].v.intRange.format = data[p++]; - break; - } - p += fieldLen; - ++rc; - } - ruleCount = rc; - return p; + int p = 0; + unsigned int rc = 0; + while (rc < maxRuleCount) { + if (p >= len) + return -1; + rules[ruleCount].t = data[p++]; + const int fieldLen = (int)data[p++]; + if ((p + fieldLen) > len) + return -1; + switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3fU)) { + default: + break; + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + if ((p + 14) > len) + return -1; + rules[ruleCount].v.fwd.address = Utils::loadBigEndian(data + p); + p += 8; + rules[ruleCount].v.fwd.flags = Utils::loadBigEndian(data + p); + p += 4; + rules[ruleCount].v.fwd.length = Utils::loadBigEndian(data + p); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + if ((p + ZT_ADDRESS_LENGTH) > len) + return -1; + rules[ruleCount].v.zt = Address(data + p).toInt(); + p += ZT_ADDRESS_LENGTH; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + if ((p + 2) > len) + return -1; + rules[ruleCount].v.vlanId = Utils::loadBigEndian(data + p); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + if ((p + 1) > len) + return -1; + rules[ruleCount].v.vlanPcp = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + if ((p + 1) > len) + return -1; + rules[ruleCount].v.vlanDei = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + if ((p + 6) > len) + return -1; + Utils::copy<6>(rules[ruleCount].v.mac, data + p); + p += 6; + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + if ((p + 5) > len) + return -1; + Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip), data + p); + p += 4; + rules[ruleCount].v.ipv4.mask = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + if ((p + 17) > len) + return -1; + Utils::copy<16>(rules[ruleCount].v.ipv6.ip, data + p); + p += 16; + rules[ruleCount].v.ipv6.mask = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + if ((p + 3) > len) + return -1; + rules[ruleCount].v.ipTos.mask = data[p++]; + rules[ruleCount].v.ipTos.value[0] = data[p++]; + rules[ruleCount].v.ipTos.value[1] = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + if ((p + 1) > len) + return -1; + rules[ruleCount].v.ipProtocol = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + if ((p + 2) > len) + return -1; + rules[ruleCount].v.etherType = Utils::loadBigEndian(data + p); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + if ((p + 3) > len) + return -1; + rules[ruleCount].v.icmp.type = data[p++]; + rules[ruleCount].v.icmp.code = data[p++]; + rules[ruleCount].v.icmp.flags = data[p++]; + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + if ((p + 4) > len) + return -1; + rules[ruleCount].v.port[0] = Utils::loadBigEndian(data + p); + p += 2; + rules[ruleCount].v.port[1] = Utils::loadBigEndian(data + p); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: + if ((p + 8) > len) + return -1; + rules[ruleCount].v.characteristics = Utils::loadBigEndian(data + p); + p += 8; + break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + if ((p + 4) > len) + return -1; + rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian(data + p); + p += 2; + rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian(data + p); + p += 2; + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + if ((p + 4) > len) + return -1; + rules[ruleCount].v.randomProbability = Utils::loadBigEndian(data + p); + p += 4; + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: + if ((p + 4) > len) + return -1; + rules[ruleCount].v.tag.id = Utils::loadBigEndian(data + p); + p += 4; + rules[ruleCount].v.tag.value = Utils::loadBigEndian(data + p); + p += 4; + break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: + if ((p + 19) > len) + return -1; + rules[ruleCount].v.intRange.start = Utils::loadBigEndian(data + p); + p += 8; + rules[ruleCount].v.intRange.end = + (uint32_t)(Utils::loadBigEndian(data + p) - rules[ruleCount].v.intRange.start); + p += 8; + rules[ruleCount].v.intRange.idx = Utils::loadBigEndian(data + p); + p += 2; + rules[ruleCount].v.intRange.format = data[p++]; + break; + } + p += fieldLen; + ++rc; + } + ruleCount = rc; + return p; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/CapabilityCredential.hpp b/core/CapabilityCredential.hpp index eced93897..3709351c1 100644 --- a/core/CapabilityCredential.hpp +++ b/core/CapabilityCredential.hpp @@ -14,15 +14,17 @@ #ifndef ZT_CAPABILITY_HPP #define ZT_CAPABILITY_HPP -#include "Constants.hpp" -#include "Credential.hpp" #include "Address.hpp" #include "C25519.hpp" -#include "Utils.hpp" +#include "Constants.hpp" +#include "Credential.hpp" #include "Identity.hpp" +#include "Utils.hpp" #define ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX 21 -#define ZT_CAPABILITY_MARSHAL_SIZE_MAX (8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 + (5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE)) +#define ZT_CAPABILITY_MARSHAL_SIZE_MAX \ + (8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 \ + + (5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE)) namespace ZeroTier { @@ -46,141 +48,180 @@ class Context; * Note that this is after evaluation of network scope rules and only if * network scope rules do not deliver an explicit match. */ -class CapabilityCredential : public Credential -{ - friend class Credential; +class CapabilityCredential : public Credential { + friend class Credential; -public: - static constexpr ZT_CredentialType credentialType() noexcept - { return ZT_CREDENTIAL_TYPE_CAPABILITY; } + public: + static constexpr ZT_CredentialType credentialType() noexcept + { + return ZT_CREDENTIAL_TYPE_CAPABILITY; + } - ZT_INLINE CapabilityCredential() noexcept - { memoryZero(this); } + ZT_INLINE CapabilityCredential() noexcept + { + memoryZero(this); + } - /** - * @param id Capability ID - * @param nwid Network ID - * @param timestamp Timestamp (at controller) - * @param mccl Maximum custody chain length (1 to create non-transferable capability) - * @param rules Network flow rules for this capability - * @param ruleCount Number of flow rules - */ - CapabilityCredential( - const uint32_t id, - const uint64_t nwid, - const int64_t timestamp, - const ZT_VirtualNetworkRule *const rules, - const unsigned int ruleCount) noexcept; + /** + * @param id Capability ID + * @param nwid Network ID + * @param timestamp Timestamp (at controller) + * @param mccl Maximum custody chain length (1 to create non-transferable capability) + * @param rules Network flow rules for this capability + * @param ruleCount Number of flow rules + */ + CapabilityCredential( + const uint32_t id, + const uint64_t nwid, + const int64_t timestamp, + const ZT_VirtualNetworkRule* const rules, + const unsigned int ruleCount) noexcept; - /** - * @return Rules -- see ruleCount() for size of array - */ - ZT_INLINE const ZT_VirtualNetworkRule *rules() const noexcept - { return m_rules; } + /** + * @return Rules -- see ruleCount() for size of array + */ + ZT_INLINE const ZT_VirtualNetworkRule* rules() const noexcept + { + return m_rules; + } - /** - * @return Number of rules in rules() - */ - ZT_INLINE unsigned int ruleCount() const noexcept - { return m_ruleCount; } + /** + * @return Number of rules in rules() + */ + ZT_INLINE unsigned int ruleCount() const noexcept + { + return m_ruleCount; + } - ZT_INLINE uint32_t id() const noexcept - { return m_id; } + ZT_INLINE uint32_t id() const noexcept + { + return m_id; + } - ZT_INLINE uint64_t networkId() const noexcept - { return m_nwid; } + ZT_INLINE uint64_t networkId() const noexcept + { + return m_nwid; + } - ZT_INLINE int64_t timestamp() const noexcept - { return m_timestamp; } + ZT_INLINE int64_t timestamp() const noexcept + { + return m_timestamp; + } - ZT_INLINE int64_t revision() const noexcept - { return m_timestamp; } + ZT_INLINE int64_t revision() const noexcept + { + return m_timestamp; + } - ZT_INLINE const Address &issuedTo() const noexcept - { return m_issuedTo; } + ZT_INLINE const Address& issuedTo() const noexcept + { + return m_issuedTo; + } - ZT_INLINE const Address &signer() const noexcept - { return m_signedBy; } + ZT_INLINE const Address& signer() const noexcept + { + return m_signedBy; + } - ZT_INLINE const uint8_t *signature() const noexcept - { return m_signature; } + ZT_INLINE const uint8_t* signature() const noexcept + { + return m_signature; + } - ZT_INLINE unsigned int signatureLength() const noexcept - { return m_signatureLength; } + ZT_INLINE unsigned int signatureLength() const noexcept + { + return m_signatureLength; + } - /** - * Sign this capability and add signature to its chain of custody - * - * If this returns false, this object should be considered to be - * in an undefined state and should be discarded. False can be returned - * if there is no more room for signatures (max chain length reached) - * or if the 'from' identity does not include a secret key to allow - * it to sign anything. - * - * @param from Signing identity (must have secret) - * @param to Recipient of this signature - * @return True if signature successful and chain of custody appended - */ - bool sign(const Identity &from, const Address &to) noexcept; + /** + * Sign this capability and add signature to its chain of custody + * + * If this returns false, this object should be considered to be + * in an undefined state and should be discarded. False can be returned + * if there is no more room for signatures (max chain length reached) + * or if the 'from' identity does not include a secret key to allow + * it to sign anything. + * + * @param from Signing identity (must have secret) + * @param to Recipient of this signature + * @return True if signature successful and chain of custody appended + */ + bool sign(const Identity& from, const Address& to) noexcept; - /** - * Verify this capability's chain of custody and signatures - * - * @param RR Runtime environment to provide for peer lookup, etc. - */ - ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept - { return s_verify(ctx, cc, *this); } + /** + * Verify this capability's chain of custody and signatures + * + * @param RR Runtime environment to provide for peer lookup, etc. + */ + ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept + { + return s_verify(ctx, cc, *this); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_CAPABILITY_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_CAPABILITY_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; - /** - * Marshal a set of virtual network rules - * - * @param data Buffer to store rules (must be at least ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX) - * @param rules Network rules - * @param ruleCount Number of rules - * @return Number of bytes written or -1 on error - */ - static int marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *rules, unsigned int ruleCount) noexcept; + /** + * Marshal a set of virtual network rules + * + * @param data Buffer to store rules (must be at least ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX) + * @param rules Network rules + * @param ruleCount Number of rules + * @return Number of bytes written or -1 on error + */ + static int + marshalVirtualNetworkRules(uint8_t* data, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount) noexcept; - /** - * Unmarshal a set of virtual network rules - * - * @param data Rule set to unmarshal - * @param len Length of data - * @param rules Buffer to store rules - * @param ruleCount Result parameter to set to the number of rules decoded - * @param maxRuleCount Capacity of rules buffer - * @return Number of bytes unmarshaled or -1 on error - */ - static int unmarshalVirtualNetworkRules(const uint8_t *data, int len, ZT_VirtualNetworkRule *rules, unsigned int &ruleCount, unsigned int maxRuleCount) noexcept; + /** + * Unmarshal a set of virtual network rules + * + * @param data Rule set to unmarshal + * @param len Length of data + * @param rules Buffer to store rules + * @param ruleCount Result parameter to set to the number of rules decoded + * @param maxRuleCount Capacity of rules buffer + * @return Number of bytes unmarshaled or -1 on error + */ + static int unmarshalVirtualNetworkRules( + const uint8_t* data, + int len, + ZT_VirtualNetworkRule* rules, + unsigned int& ruleCount, + unsigned int maxRuleCount) noexcept; - // Provides natural sort order by ID - ZT_INLINE bool operator<(const CapabilityCredential &c) const noexcept - { return (m_id < c.m_id); } + // Provides natural sort order by ID + ZT_INLINE bool operator<(const CapabilityCredential& c) const noexcept + { + return (m_id < c.m_id); + } - ZT_INLINE bool operator==(const CapabilityCredential &c) const noexcept - { return (memcmp(this, &c, sizeof(CapabilityCredential)) == 0); } + ZT_INLINE bool operator==(const CapabilityCredential& c) const noexcept + { + return (memcmp(this, &c, sizeof(CapabilityCredential)) == 0); + } - ZT_INLINE bool operator!=(const CapabilityCredential &c) const noexcept - { return (memcmp(this, &c, sizeof(CapabilityCredential)) != 0); } + ZT_INLINE bool operator!=(const CapabilityCredential& c) const noexcept + { + return (memcmp(this, &c, sizeof(CapabilityCredential)) != 0); + } -private: - uint64_t m_nwid; - int64_t m_timestamp; - uint32_t m_id; - unsigned int m_ruleCount; - ZT_VirtualNetworkRule m_rules[ZT_MAX_CAPABILITY_RULES]; - Address m_issuedTo; - Address m_signedBy; - unsigned int m_signatureLength; - uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; + private: + uint64_t m_nwid; + int64_t m_timestamp; + uint32_t m_id; + unsigned int m_ruleCount; + ZT_VirtualNetworkRule m_rules[ZT_MAX_CAPABILITY_RULES]; + Address m_issuedTo; + Address m_signedBy; + unsigned int m_signatureLength; + uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Certificate.cpp b/core/Certificate.cpp index 2d82f3e1f..73daf6c73 100644 --- a/core/Certificate.cpp +++ b/core/Certificate.cpp @@ -12,622 +12,687 @@ /****/ #include "Certificate.hpp" -#include "SHA512.hpp" + #include "ECC384.hpp" +#include "SHA512.hpp" #include "ScopedPtr.hpp" namespace ZeroTier { Certificate::Certificate() noexcept { - ZT_Certificate *const sup = this; - Utils::zero< sizeof(ZT_Certificate) >(sup); + ZT_Certificate* const sup = this; + Utils::zero(sup); } -Certificate::Certificate(const ZT_Certificate &apiCert) : - Certificate() -{ *this = apiCert; } +Certificate::Certificate(const ZT_Certificate& apiCert) : Certificate() +{ + *this = apiCert; +} -Certificate::Certificate(const Certificate &cert) : - Certificate() -{ *this = cert; } +Certificate::Certificate(const Certificate& cert) : Certificate() +{ + *this = cert; +} Certificate::~Certificate() -{} - -Certificate &Certificate::operator=(const ZT_Certificate &cert) { - m_clear(); - - Utils::copy< sizeof(this->serialNo) >(this->serialNo, cert.serialNo); - this->usageFlags = cert.usageFlags; - this->timestamp = cert.timestamp; - this->validity[0] = cert.validity[0]; - this->validity[1] = cert.validity[1]; - - this->subject.timestamp = cert.subject.timestamp; - - if (cert.subject.identities != nullptr) { - for (unsigned int i = 0; i < cert.subject.identityCount; ++i) { - if (cert.subject.identities[i].identity) { - if (cert.subject.identities[i].locator) { - addSubjectIdentity(*reinterpret_cast(cert.subject.identities[i].identity), *reinterpret_cast(cert.subject.identities[i].locator)); - } else { - addSubjectIdentity(*reinterpret_cast(cert.subject.identities[i].identity)); - } - } - } - } - - if (cert.subject.networks != nullptr) { - for (unsigned int i = 0; i < cert.subject.networkCount; ++i) { - if (cert.subject.networks[i].id) { - addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller); - } - } - } - - if (cert.subject.updateURLs != nullptr) { - for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) { - if (cert.subject.updateURLs[i]) { - addSubjectUpdateUrl(cert.subject.updateURLs[i]); - } - } - } - - this->subject.identityCount = cert.subject.identityCount; - this->subject.networkCount = cert.subject.networkCount; - this->subject.updateURLCount = cert.subject.updateURLCount; - - Utils::copy< sizeof(ZT_Certificate_Name) >(&(this->subject.name), &(cert.subject.name)); - - Utils::copy< sizeof(this->subject.uniqueId) >(this->subject.uniqueId, cert.subject.uniqueId); - Utils::copy< sizeof(this->subject.uniqueIdSignature) >(this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature); - this->subject.uniqueIdSize = cert.subject.uniqueIdSize; - this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize; - - Utils::copy< sizeof(this->issuer) >(this->issuer, cert.issuer); - - Utils::copy< sizeof(this->issuerPublicKey) >(this->issuerPublicKey, cert.issuerPublicKey); - Utils::copy< sizeof(this->publicKey) >(this->publicKey, cert.publicKey); - this->issuerPublicKeySize = cert.issuerPublicKeySize; - this->publicKeySize = cert.publicKeySize; - - if ((cert.extendedAttributes != nullptr) && (cert.extendedAttributesSize > 0)) { - m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize); - this->extendedAttributes = m_extendedAttributes.data(); - this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); - } - - Utils::copy< sizeof(this->signature) >(this->signature, cert.signature); - this->signatureSize = cert.signatureSize; - - this->maxPathLength = cert.maxPathLength; - - return *this; } -ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id) +Certificate& Certificate::operator=(const ZT_Certificate& cert) { - // Store a local copy of the actual identity. - m_identities.push_front(id); - m_identities.front().erasePrivateKey(); + m_clear(); - // Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array. - m_subjectIdentities.push_back(ZT_Certificate_Identity()); - m_subjectIdentities.back().identity = &(m_identities.front()); - m_subjectIdentities.back().locator = nullptr; + Utils::copyserialNo)>(this->serialNo, cert.serialNo); + this->usageFlags = cert.usageFlags; + this->timestamp = cert.timestamp; + this->validity[0] = cert.validity[0]; + this->validity[1] = cert.validity[1]; - this->subject.identities = m_subjectIdentities.data(); - this->subject.identityCount = (unsigned int)m_subjectIdentities.size(); + this->subject.timestamp = cert.subject.timestamp; - return &(m_subjectIdentities.back()); + if (cert.subject.identities != nullptr) { + for (unsigned int i = 0; i < cert.subject.identityCount; ++i) { + if (cert.subject.identities[i].identity) { + if (cert.subject.identities[i].locator) { + addSubjectIdentity( + *reinterpret_cast(cert.subject.identities[i].identity), + *reinterpret_cast(cert.subject.identities[i].locator)); + } + else { + addSubjectIdentity(*reinterpret_cast(cert.subject.identities[i].identity)); + } + } + } + } + + if (cert.subject.networks != nullptr) { + for (unsigned int i = 0; i < cert.subject.networkCount; ++i) { + if (cert.subject.networks[i].id) { + addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller); + } + } + } + + if (cert.subject.updateURLs != nullptr) { + for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) { + if (cert.subject.updateURLs[i]) { + addSubjectUpdateUrl(cert.subject.updateURLs[i]); + } + } + } + + this->subject.identityCount = cert.subject.identityCount; + this->subject.networkCount = cert.subject.networkCount; + this->subject.updateURLCount = cert.subject.updateURLCount; + + Utils::copy(&(this->subject.name), &(cert.subject.name)); + + Utils::copysubject.uniqueId)>(this->subject.uniqueId, cert.subject.uniqueId); + Utils::copysubject.uniqueIdSignature)>( + this->subject.uniqueIdSignature, + cert.subject.uniqueIdSignature); + this->subject.uniqueIdSize = cert.subject.uniqueIdSize; + this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize; + + Utils::copyissuer)>(this->issuer, cert.issuer); + + Utils::copyissuerPublicKey)>(this->issuerPublicKey, cert.issuerPublicKey); + Utils::copypublicKey)>(this->publicKey, cert.publicKey); + this->issuerPublicKeySize = cert.issuerPublicKeySize; + this->publicKeySize = cert.publicKeySize; + + if ((cert.extendedAttributes != nullptr) && (cert.extendedAttributesSize > 0)) { + m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize); + this->extendedAttributes = m_extendedAttributes.data(); + this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); + } + + Utils::copysignature)>(this->signature, cert.signature); + this->signatureSize = cert.signatureSize; + + this->maxPathLength = cert.maxPathLength; + + return *this; } -ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, const Locator &loc) +ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id) { - // Add identity as above. - ZT_Certificate_Identity *const n = addSubjectIdentity(id); + // Store a local copy of the actual identity. + m_identities.push_front(id); + m_identities.front().erasePrivateKey(); - // Store local copy of locator. - m_locators.push_front(loc); + // Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array. + m_subjectIdentities.push_back(ZT_Certificate_Identity()); + m_subjectIdentities.back().identity = &(m_identities.front()); + m_subjectIdentities.back().locator = nullptr; - // Set pointer to stored local copy of locator. - n->locator = &(m_locators.front()); + this->subject.identities = m_subjectIdentities.data(); + this->subject.identityCount = (unsigned int)m_subjectIdentities.size(); - return n; + return &(m_subjectIdentities.back()); } -ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller) +ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id, const Locator& loc) { - // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array. - m_subjectNetworks.resize(++this->subject.networkCount); - this->subject.networks = m_subjectNetworks.data(); + // Add identity as above. + ZT_Certificate_Identity* const n = addSubjectIdentity(id); - // Set fields in new ZT_Certificate_Network structure. - m_subjectNetworks.back().id = id; - Utils::copy< sizeof(ZT_Fingerprint) >(&(m_subjectNetworks.back().controller), &controller); + // Store local copy of locator. + m_locators.push_front(loc); - return &(m_subjectNetworks.back()); + // Set pointer to stored local copy of locator. + n->locator = &(m_locators.front()); + + return n; } -void Certificate::addSubjectUpdateUrl(const char *url) +ZT_Certificate_Network* Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint& controller) { - if ((url != nullptr) && (url[0] != 0)) { - // Store local copy of URL. - m_strings.push_front(url); + // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array. + m_subjectNetworks.resize(++this->subject.networkCount); + this->subject.networks = m_subjectNetworks.data(); - // Add pointer to local copy to pointer array and update C structure to point to - // potentially reallocated array. - m_updateUrls.push_back(m_strings.front().c_str()); - this->subject.updateURLs = m_updateUrls.data(); - this->subject.updateURLCount = (unsigned int)m_updateUrls.size(); - } + // Set fields in new ZT_Certificate_Network structure. + m_subjectNetworks.back().id = id; + Utils::copy(&(m_subjectNetworks.back().controller), &controller); + + return &(m_subjectNetworks.back()); } -Vector< uint8_t > Certificate::encode(const bool omitSignature) const +void Certificate::addSubjectUpdateUrl(const char* url) { - Vector< uint8_t > enc; - Dictionary d; + if ((url != nullptr) && (url[0] != 0)) { + // Store local copy of URL. + m_strings.push_front(url); - /* - * A Dictionary is used to encode certificates as it's a common and extensible - * format. Custom packed formats are used for credentials as these are smaller - * and faster to marshal/unmarshal. - * - * We use the slower actually-insert-keys method of building a dictionary - * instead of the faster append method because for signing and verification - * purposes the keys must be always be in order. - */ - - if (this->usageFlags != 0) - d.add("f", this->usageFlags); - if (this->timestamp > 0) - d.add("t", (uint64_t)this->timestamp); - if (this->validity[0] > 0) - d.add("v#0", (uint64_t)this->validity[0]); - if (this->validity[1] > 0) - d.add("v#1", (uint64_t)this->validity[1]); - - m_encodeSubject(this->subject, d, false); - - if (!Utils::allZero(this->issuer, sizeof(this->issuer))) - d.add("i", this->issuer, sizeof(this->issuer)); - - if (this->issuerPublicKeySize > 0) - d.add("iPK", this->issuerPublicKey, this->issuerPublicKeySize); - - if (this->publicKeySize > 0) - d.add("pK", this->publicKey, this->publicKeySize); - - if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0)) - d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize); - - if ((!omitSignature) && (this->signatureSize > 0)) - d["si"].assign(this->signature, this->signature + this->signatureSize); - - if (this->maxPathLength > 0) - d.add("l", (uint64_t)this->maxPathLength); - - d.encode(enc); - return enc; + // Add pointer to local copy to pointer array and update C structure to point to + // potentially reallocated array. + m_updateUrls.push_back(m_strings.front().c_str()); + this->subject.updateURLs = m_updateUrls.data(); + this->subject.updateURLCount = (unsigned int)m_updateUrls.size(); + } } -bool Certificate::decode(const void *const data, const unsigned int len) +Vector Certificate::encode(const bool omitSignature) const { - char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + Vector enc; + Dictionary d; - Dictionary d; - if (!d.decode(data, len)) - return false; + /* + * A Dictionary is used to encode certificates as it's a common and extensible + * format. Custom packed formats are used for credentials as these are smaller + * and faster to marshal/unmarshal. + * + * We use the slower actually-insert-keys method of building a dictionary + * instead of the faster append method because for signing and verification + * purposes the keys must be always be in order. + */ - m_clear(); + if (this->usageFlags != 0) + d.add("f", this->usageFlags); + if (this->timestamp > 0) + d.add("t", (uint64_t)this->timestamp); + if (this->validity[0] > 0) + d.add("v#0", (uint64_t)this->validity[0]); + if (this->validity[1] > 0) + d.add("v#1", (uint64_t)this->validity[1]); - this->usageFlags = d.getUI("f"); - this->timestamp = (int64_t)d.getUI("t"); - this->validity[0] = (int64_t)d.getUI("v#0"); - this->validity[1] = (int64_t)d.getUI("v#1"); + m_encodeSubject(this->subject, d, false); - this->subject.timestamp = (int64_t)d.getUI("s.t"); + if (! Utils::allZero(this->issuer, sizeof(this->issuer))) + d.add("i", this->issuer, sizeof(this->issuer)); - unsigned int cnt = (unsigned int)d.getUI("s.i$"); - for (unsigned int i = 0; i < cnt; ++i) { - const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)]; - const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)]; - if (identityData.empty()) - return false; - Identity id; - if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) - return false; - if (locatorData.empty()) { - this->addSubjectIdentity(id); - } else { - Locator loc; - if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) - return false; - this->addSubjectIdentity(id, loc); - } - } + if (this->issuerPublicKeySize > 0) + d.add("iPK", this->issuerPublicKey, this->issuerPublicKeySize); - cnt = (unsigned int)d.getUI("s.nw$"); - for (unsigned int i = 0; i < cnt; ++i) { - const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i)); - const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)]; - if ((nwid == 0) || (fingerprintData.empty())) - return false; - Fingerprint fp; - if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) - return false; - this->addSubjectNetwork(nwid, fp); - } + if (this->publicKeySize > 0) + d.add("pK", this->publicKey, this->publicKeySize); - cnt = (unsigned int)d.getUI("s.u$"); - for (unsigned int i = 0; i < cnt; ++i) - addSubjectUpdateUrl(d.getS(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), tmp2, sizeof(tmp2))); + if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0)) + d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize); - d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo)); - d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName)); - d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country)); - d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization)); - d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit)); - d.getS("s.n.l", this->subject.name.locality, sizeof(this->subject.name.locality)); - d.getS("s.n.p", this->subject.name.province, sizeof(this->subject.name.province)); - d.getS("s.n.sA", this->subject.name.streetAddress, sizeof(this->subject.name.streetAddress)); - d.getS("s.n.pC", this->subject.name.postalCode, sizeof(this->subject.name.postalCode)); - d.getS("s.n.e", this->subject.name.email, sizeof(this->subject.name.email)); - d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url)); - d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host)); + if ((! omitSignature) && (this->signatureSize > 0)) + d["si"].assign(this->signature, this->signature + this->signatureSize); - const Vector< uint8_t > &uniqueId = d["s.uI"]; - if ((!uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) { - Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size()); - this->subject.uniqueIdSize = (unsigned int)uniqueId.size(); - } - const Vector< uint8_t > &uniqueIdSignature = d["s.uS"]; - if ((!uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) { - Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size()); - this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size(); - } + if (this->maxPathLength > 0) + d.add("l", (uint64_t)this->maxPathLength); - const Vector< uint8_t > &issuerData = d["i"]; - if (issuerData.size() == sizeof(this->issuer)) { - Utils::copy< sizeof(this->issuer) >(this->issuer, issuerData.data()); - } - - const Vector< uint8_t > &issuerPublicKey = d["iPK"]; - if ((!issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) { - Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size()); - this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size(); - } - - const Vector< uint8_t > &publicKey = d["pK"]; - if ((!publicKey.empty()) && (publicKey.size() <= sizeof(this->publicKey))) { - Utils::copy(this->publicKey, publicKey.data(), publicKey.size()); - this->publicKeySize = (unsigned int)publicKey.size(); - } - - m_extendedAttributes = d["x"]; - if (!m_extendedAttributes.empty()) { - this->extendedAttributes = m_extendedAttributes.data(); - this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); - } - - const Vector< uint8_t > &signature = d["si"]; - if ((!signature.empty()) && (signature.size() <= sizeof(this->signature))) { - Utils::copy(this->signature, signature.data(), signature.size()); - this->signatureSize = (unsigned int)signature.size(); - } - - this->maxPathLength = (unsigned int)d.getUI("l"); - - const Vector< uint8_t > enc(encode(true)); - SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); - - return true; + d.encode(enc); + return enc; } -bool Certificate::sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *const issuerPrivateKey, const unsigned int issuerPrivateKeySize) +bool Certificate::decode(const void* const data, const unsigned int len) { - if ((!issuerPrivateKey) || (issuerPrivateKeySize == 0)) - return false; + char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - switch (reinterpret_cast(issuerPrivateKey)[0]) { - default: - return false; - case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: - if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) { - Utils::copy< sizeof(this->issuer) >(this->issuer, issuer); - Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(this->issuerPublicKey, issuerPrivateKey); // private is prefixed with public - this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; + Dictionary d; + if (! d.decode(data, len)) + return false; - const Vector< uint8_t > enc(encode(true)); - SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); + m_clear(); - ECC384ECDSASign(reinterpret_cast(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo, this->signature); - this->signatureSize = ZT_ECC384_SIGNATURE_SIZE; + this->usageFlags = d.getUI("f"); + this->timestamp = (int64_t)d.getUI("t"); + this->validity[0] = (int64_t)d.getUI("v#0"); + this->validity[1] = (int64_t)d.getUI("v#1"); - return true; - } - break; - } + this->subject.timestamp = (int64_t)d.getUI("s.t"); - return false; + unsigned int cnt = (unsigned int)d.getUI("s.i$"); + for (unsigned int i = 0; i < cnt; ++i) { + const Vector& identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)]; + const Vector& locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)]; + if (identityData.empty()) + return false; + Identity id; + if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) + return false; + if (locatorData.empty()) { + this->addSubjectIdentity(id); + } + else { + Locator loc; + if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) + return false; + this->addSubjectIdentity(id, loc); + } + } + + cnt = (unsigned int)d.getUI("s.nw$"); + for (unsigned int i = 0; i < cnt; ++i) { + const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i)); + const Vector& fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)]; + if ((nwid == 0) || (fingerprintData.empty())) + return false; + Fingerprint fp; + if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) + return false; + this->addSubjectNetwork(nwid, fp); + } + + cnt = (unsigned int)d.getUI("s.u$"); + for (unsigned int i = 0; i < cnt; ++i) + addSubjectUpdateUrl(d.getS(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), tmp2, sizeof(tmp2))); + + d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo)); + d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName)); + d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country)); + d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization)); + d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit)); + d.getS("s.n.l", this->subject.name.locality, sizeof(this->subject.name.locality)); + d.getS("s.n.p", this->subject.name.province, sizeof(this->subject.name.province)); + d.getS("s.n.sA", this->subject.name.streetAddress, sizeof(this->subject.name.streetAddress)); + d.getS("s.n.pC", this->subject.name.postalCode, sizeof(this->subject.name.postalCode)); + d.getS("s.n.e", this->subject.name.email, sizeof(this->subject.name.email)); + d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url)); + d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host)); + + const Vector& uniqueId = d["s.uI"]; + if ((! uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) { + Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size()); + this->subject.uniqueIdSize = (unsigned int)uniqueId.size(); + } + const Vector& uniqueIdSignature = d["s.uS"]; + if ((! uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) { + Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size()); + this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size(); + } + + const Vector& issuerData = d["i"]; + if (issuerData.size() == sizeof(this->issuer)) { + Utils::copyissuer)>(this->issuer, issuerData.data()); + } + + const Vector& issuerPublicKey = d["iPK"]; + if ((! issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) { + Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size()); + this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size(); + } + + const Vector& publicKey = d["pK"]; + if ((! publicKey.empty()) && (publicKey.size() <= sizeof(this->publicKey))) { + Utils::copy(this->publicKey, publicKey.data(), publicKey.size()); + this->publicKeySize = (unsigned int)publicKey.size(); + } + + m_extendedAttributes = d["x"]; + if (! m_extendedAttributes.empty()) { + this->extendedAttributes = m_extendedAttributes.data(); + this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); + } + + const Vector& signature = d["si"]; + if ((! signature.empty()) && (signature.size() <= sizeof(this->signature))) { + Utils::copy(this->signature, signature.data(), signature.size()); + this->signatureSize = (unsigned int)signature.size(); + } + + this->maxPathLength = (unsigned int)d.getUI("l"); + + const Vector enc(encode(true)); + SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); + + return true; +} + +bool Certificate::sign( + const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], + const void* const issuerPrivateKey, + const unsigned int issuerPrivateKeySize) +{ + if ((! issuerPrivateKey) || (issuerPrivateKeySize == 0)) + return false; + + switch (reinterpret_cast(issuerPrivateKey)[0]) { + default: + return false; + case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: + if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) { + Utils::copyissuer)>(this->issuer, issuer); + Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>( + this->issuerPublicKey, + issuerPrivateKey); // private is prefixed with public + this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; + + const Vector enc(encode(true)); + SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); + + ECC384ECDSASign( + reinterpret_cast(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, + this->serialNo, + this->signature); + this->signatureSize = ZT_ECC384_SIGNATURE_SIZE; + + return true; + } + break; + } + + return false; } ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSignatures) const { - try { - if (this->validity[0] > this->validity[1]) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + try { + if (this->validity[0] > this->validity[1]) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - if (this->subject.identityCount > 0) { - if (this->subject.identities) { - for (unsigned int i = 0; i < this->subject.identityCount; ++i) { - if (!this->subject.identities[i].identity) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } - if (checkSignatures) { - if (!reinterpret_cast(this->subject.identities[i].identity)->locallyValidate()) { - return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY; - } - if ((this->subject.identities[i].locator) && (!reinterpret_cast(this->subject.identities[i].locator)->verify(*reinterpret_cast(this->subject.identities[i].identity)))) { - return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE; - } - } - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } - } + if (this->subject.identityCount > 0) { + if (this->subject.identities) { + for (unsigned int i = 0; i < this->subject.identityCount; ++i) { + if (! this->subject.identities[i].identity) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } + if (checkSignatures) { + if (! reinterpret_cast(this->subject.identities[i].identity) + ->locallyValidate()) { + return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY; + } + if ((this->subject.identities[i].locator) + && (! reinterpret_cast(this->subject.identities[i].locator) + ->verify( + *reinterpret_cast(this->subject.identities[i].identity)))) { + return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE; + } + } + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } + } - if (this->subject.networkCount > 0) { - if (this->subject.networks) { - for (unsigned int i = 0; i < this->subject.networkCount; ++i) { - if (!this->subject.networks[i].id) { - return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; - } - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } - } + if (this->subject.networkCount > 0) { + if (this->subject.networks) { + for (unsigned int i = 0; i < this->subject.networkCount; ++i) { + if (! this->subject.networks[i].id) { + return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; + } + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } + } - if (this->subject.updateURLCount > 0) { - if (this->subject.updateURLs) { - for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) { - if (!this->subject.updateURLs[i]) - return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; - } - } else { - return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; - } - } + if (this->subject.updateURLCount > 0) { + if (this->subject.updateURLs) { + for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) { + if (! this->subject.updateURLs[i]) + return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; + } + } + else { + return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; + } + } - if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) + || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - if ((this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) || (this->publicKeySize > sizeof(this->publicKey))) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + if ((this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) + || (this->publicKeySize > sizeof(this->publicKey))) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - if ((this->extendedAttributesSize > 0) && (!this->extendedAttributes)) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + if ((this->extendedAttributesSize > 0) && (! this->extendedAttributes)) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - if (this->signatureSize > sizeof(this->signature)) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + if (this->signatureSize > sizeof(this->signature)) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - if (checkSignatures) { - // Signature check fails if main signature is not present or invalid. - // Note that the serial number / SHA384 hash is computed on decode(), so - // this value is not something we blindly trust from input. - if ((this->issuerPublicKeySize > 0) && (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) { - switch (this->issuerPublicKey[0]) { - case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: - if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) { - if (!ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) { - return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; - } - break; - default: - return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; - } + if (checkSignatures) { + // Signature check fails if main signature is not present or invalid. + // Note that the serial number / SHA384 hash is computed on decode(), so + // this value is not something we blindly trust from input. + if ((this->issuerPublicKeySize > 0) + && (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) { + switch (this->issuerPublicKey[0]) { + case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: + if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) + && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) { + if (! ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) { + return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; + } + break; + default: + return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; + } - // Subject unique ID signatures are optional, so this only fails if it - // is present and invalid. A unique ID with type ALGORITHM_NONE is also - // allowed, but this means its signature is not checked. - if (this->subject.uniqueIdSize > 0) { - if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) { - switch (this->subject.uniqueId[0]) { - case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE: - break; - case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: - if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) { - Dictionary d; - m_encodeSubject(this->subject, d, true); + // Subject unique ID signatures are optional, so this only fails if it + // is present and invalid. A unique ID with type ALGORITHM_NONE is also + // allowed, but this means its signature is not checked. + if (this->subject.uniqueIdSize > 0) { + if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) { + switch (this->subject.uniqueId[0]) { + case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE: + break; + case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: + if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) + && (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) { + Dictionary d; + m_encodeSubject(this->subject, d, true); - Vector< uint8_t > enc; - enc.reserve(1024); - d.encode(enc); + Vector enc; + enc.reserve(1024); + d.encode(enc); - static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "ECC384 should take 384-bit hash"); - uint8_t h[ZT_SHA384_DIGEST_SIZE]; - SHA384(h, enc.data(), (unsigned int)enc.size()); + static_assert( + ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, + "ECC384 should take 384-bit hash"); + uint8_t h[ZT_SHA384_DIGEST_SIZE]; + SHA384(h, enc.data(), (unsigned int)enc.size()); - if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) { - return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; - } - break; - default: - return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; - } - } else { - return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; - } - } - } + if (! ECC384ECDSAVerify( + this->subject.uniqueId + 1, + h, + this->subject.uniqueIdSignature)) { + return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; + } + break; + default: + return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; + } + } + else { + return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; + } + } + } - if (clock >= 0) { - if (!this->verifyTimeWindow(clock)) - return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; - } - } catch (...) { - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } + if (clock >= 0) { + if (! this->verifyTimeWindow(clock)) + return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; + } + } + catch (...) { + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } - return ZT_CERTIFICATE_ERROR_NONE; + return ZT_CERTIFICATE_ERROR_NONE; } -bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize) +bool Certificate::newKeyPair( + const ZT_CertificatePublicKeyAlgorithm type, + uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], + int* const publicKeySize, + uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], + int* const privateKeySize) { - switch (type) { - case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: - publicKey[0] = (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384; - ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1); - ZeroTier::Utils::copy< ZT_ECC384_PUBLIC_KEY_SIZE + 1 >(privateKey, publicKey); - *publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1; - *privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE; - return true; - default: - break; - } - return false; + switch (type) { + case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: + publicKey[0] = (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384; + ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1); + ZeroTier::Utils::copy(privateKey, publicKey); + *publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1; + *privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE; + return true; + default: + break; + } + return false; } -Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *const certificatePublicKey, const unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) +Vector Certificate::createCSR( + const ZT_Certificate_Subject& s, + const void* const certificatePublicKey, + const unsigned int certificatePublicKeySize, + const void* uniqueIdPrivate, + unsigned int uniqueIdPrivateSize) { - Vector< uint8_t > enc; + Vector enc; - ZT_Certificate_Subject sc; - Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s); + ZT_Certificate_Subject sc; + Utils::copy(&sc, &s); - if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) { - Dictionary d; - m_encodeSubject(sc, d, false); - if (certificatePublicKeySize > 0) - d.add("pK", certificatePublicKey, certificatePublicKeySize); - d.encode(enc); - } + if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) { + Dictionary d; + m_encodeSubject(sc, d, false); + if (certificatePublicKeySize > 0) + d.add("pK", certificatePublicKey, certificatePublicKeySize); + d.encode(enc); + } - return enc; + return enc; } void Certificate::m_clear() { - ZT_Certificate *const sup = this; - Utils::zero< sizeof(ZT_Certificate) >(sup); + ZT_Certificate* const sup = this; + Utils::zero(sup); - m_identities.clear(); - m_locators.clear(); - m_strings.clear(); + m_identities.clear(); + m_locators.clear(); + m_strings.clear(); - m_subjectIdentities.clear(); - m_subjectNetworks.clear(); - m_updateUrls.clear(); - m_extendedAttributes.clear(); + m_subjectIdentities.clear(); + m_subjectNetworks.clear(); + m_updateUrls.clear(); + m_extendedAttributes.clear(); } -bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) +bool Certificate::m_setSubjectUniqueId( + ZT_Certificate_Subject& s, + const void* uniqueIdPrivate, + unsigned int uniqueIdPrivateSize) { - if (uniqueIdPrivateSize > 0) { - if ((uniqueIdPrivate != nullptr) && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) && (reinterpret_cast(uniqueIdPrivate)[0] == (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) { - Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(s.uniqueId, uniqueIdPrivate); - s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public + if (uniqueIdPrivateSize > 0) { + if ((uniqueIdPrivate != nullptr) + && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) + && (reinterpret_cast(uniqueIdPrivate)[0] + == (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) { + Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>(s.uniqueId, uniqueIdPrivate); + s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public - Vector< uint8_t > enc; - Dictionary d; - m_encodeSubject(s, d, true); - d.encode(enc); + Vector enc; + Dictionary d; + m_encodeSubject(s, d, true); + d.encode(enc); - uint8_t h[ZT_SHA384_DIGEST_SIZE]; - SHA384(h, enc.data(), (unsigned int)enc.size()); + uint8_t h[ZT_SHA384_DIGEST_SIZE]; + SHA384(h, enc.data(), (unsigned int)enc.size()); - ECC384ECDSASign(reinterpret_cast(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, h, s.uniqueIdSignature); - s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE; - } else { - return false; - } - } else { - Utils::zero< sizeof(s.uniqueId) >(s.uniqueId); - s.uniqueIdSize = 0; - Utils::zero< sizeof(s.uniqueIdSignature) >(s.uniqueIdSignature); - s.uniqueIdSignatureSize = 0; - } - return true; + ECC384ECDSASign( + reinterpret_cast(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, + h, + s.uniqueIdSignature); + s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE; + } + else { + return false; + } + } + else { + Utils::zero(s.uniqueId); + s.uniqueIdSize = 0; + Utils::zero(s.uniqueIdSignature); + s.uniqueIdSignatureSize = 0; + } + return true; } -void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature) +void Certificate::m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d, bool omitUniqueIdProofSignature) { - char tmp[32]; + char tmp[32]; - d.add("s.t", (uint64_t)s.timestamp); + d.add("s.t", (uint64_t)s.timestamp); - if (s.identities) { - d.add("s.i$", (uint64_t)s.identityCount); - for (unsigned int i = 0; i < s.identityCount; ++i) { - if (s.identities[i].identity) - d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), *reinterpret_cast(s.identities[i].identity)); - if (s.identities[i].locator) - d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i), *reinterpret_cast(s.identities[i].locator)); - } - } + if (s.identities) { + d.add("s.i$", (uint64_t)s.identityCount); + for (unsigned int i = 0; i < s.identityCount; ++i) { + if (s.identities[i].identity) + d.addO( + Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), + *reinterpret_cast(s.identities[i].identity)); + if (s.identities[i].locator) + d.addO( + Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i), + *reinterpret_cast(s.identities[i].locator)); + } + } - if (s.networks) { - d.add("s.nw$", (uint64_t)s.networkCount); - for (unsigned int i = 0; i < s.networkCount; ++i) { - d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i), s.networks[i].id); - Fingerprint fp(s.networks[i].controller); - d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i), fp); - } - } + if (s.networks) { + d.add("s.nw$", (uint64_t)s.networkCount); + for (unsigned int i = 0; i < s.networkCount; ++i) { + d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i), s.networks[i].id); + Fingerprint fp(s.networks[i].controller); + d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i), fp); + } + } - if (s.updateURLs) { - d.add("s.u$", (uint64_t)s.updateURLCount); - for (unsigned int i = 0; i < s.updateURLCount; ++i) - d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), s.updateURLs[i]); - } + if (s.updateURLs) { + d.add("s.u$", (uint64_t)s.updateURLCount); + for (unsigned int i = 0; i < s.updateURLCount; ++i) + d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), s.updateURLs[i]); + } - if (s.name.country[0]) - d.add("s.n.c", s.name.country); - if (s.name.organization[0]) - d.add("s.n.o", s.name.organization); - if (s.name.unit[0]) - d.add("s.n.u", s.name.unit); - if (s.name.locality[0]) - d.add("s.n.l", s.name.locality); - if (s.name.province[0]) - d.add("s.n.p", s.name.province); - if (s.name.streetAddress[0]) - d.add("s.n.sA", s.name.streetAddress); - if (s.name.postalCode[0]) - d.add("s.n.pC", s.name.postalCode); - if (s.name.commonName[0]) - d.add("s.n.cN", s.name.commonName); - if (s.name.serialNo[0]) - d.add("s.n.sN", s.name.serialNo); - if (s.name.email[0]) - d.add("s.n.e", s.name.email); - if (s.name.url[0]) - d.add("s.n.ur", s.name.url); - if (s.name.host[0]) - d.add("s.n.h", s.name.host); + if (s.name.country[0]) + d.add("s.n.c", s.name.country); + if (s.name.organization[0]) + d.add("s.n.o", s.name.organization); + if (s.name.unit[0]) + d.add("s.n.u", s.name.unit); + if (s.name.locality[0]) + d.add("s.n.l", s.name.locality); + if (s.name.province[0]) + d.add("s.n.p", s.name.province); + if (s.name.streetAddress[0]) + d.add("s.n.sA", s.name.streetAddress); + if (s.name.postalCode[0]) + d.add("s.n.pC", s.name.postalCode); + if (s.name.commonName[0]) + d.add("s.n.cN", s.name.commonName); + if (s.name.serialNo[0]) + d.add("s.n.sN", s.name.serialNo); + if (s.name.email[0]) + d.add("s.n.e", s.name.email); + if (s.name.url[0]) + d.add("s.n.ur", s.name.url); + if (s.name.host[0]) + d.add("s.n.h", s.name.host); - if (s.uniqueIdSize > 0) - d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize); - if ((!omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0)) - d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize); + if (s.uniqueIdSize > 0) + d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize); + if ((! omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0)) + d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Certificate.hpp b/core/Certificate.hpp index 2e9840a61..2269ebcce 100644 --- a/core/Certificate.hpp +++ b/core/Certificate.hpp @@ -14,15 +14,15 @@ #ifndef ZT_CERTIFICATE_HPP #define ZT_CERTIFICATE_HPP -#include "Constants.hpp" -#include "SHA512.hpp" #include "C25519.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Dictionary.hpp" #include "ECC384.hpp" #include "Identity.hpp" #include "Locator.hpp" -#include "Dictionary.hpp" +#include "SHA512.hpp" #include "Utils.hpp" -#include "Containers.hpp" namespace ZeroTier { @@ -43,188 +43,222 @@ namespace ZeroTier { * field, so these will not work correctly before sign() or decode() is * called. */ -class Certificate : public ZT_Certificate -{ -public: - Certificate() noexcept; - explicit Certificate(const ZT_Certificate &apiCert); - Certificate(const Certificate &cert); - ~Certificate(); +class Certificate : public ZT_Certificate { + public: + Certificate() noexcept; + explicit Certificate(const ZT_Certificate& apiCert); + Certificate(const Certificate& cert); + ~Certificate(); - Certificate &operator=(const ZT_Certificate &cert); + Certificate& operator=(const ZT_Certificate& cert); - ZT_INLINE Certificate &operator=(const Certificate &cert) noexcept - { - if (likely(&cert != this)) { - const ZT_Certificate *const sup = &cert; - *this = *sup; - } - return *this; - } + ZT_INLINE Certificate& operator=(const Certificate& cert) noexcept + { + if (likely(&cert != this)) { + const ZT_Certificate* const sup = &cert; + *this = *sup; + } + return *this; + } - ZT_INLINE H384 getSerialNo() const noexcept - { return H384(this->serialNo); } + ZT_INLINE H384 getSerialNo() const noexcept + { + return H384(this->serialNo); + } - /** - * Add a subject node/identity without a locator - * - * @param id Identity - * @return Pointer to C struct - */ - ZT_Certificate_Identity *addSubjectIdentity(const Identity &id); + /** + * Add a subject node/identity without a locator + * + * @param id Identity + * @return Pointer to C struct + */ + ZT_Certificate_Identity* addSubjectIdentity(const Identity& id); - /** - * Add a subject node/identity with a locator - * - * @param id Identity - * @param loc Locator signed by identity (signature is NOT checked here) - * @return Pointer to C struct - */ - ZT_Certificate_Identity *addSubjectIdentity(const Identity &id, const Locator &loc); + /** + * Add a subject node/identity with a locator + * + * @param id Identity + * @param loc Locator signed by identity (signature is NOT checked here) + * @return Pointer to C struct + */ + ZT_Certificate_Identity* addSubjectIdentity(const Identity& id, const Locator& loc); - /** - * Add a subject network - * - * @param id Network ID - * @param controller Network controller's full fingerprint - * @return Pointer to C struct - */ - ZT_Certificate_Network *addSubjectNetwork(uint64_t id, const ZT_Fingerprint &controller); + /** + * Add a subject network + * + * @param id Network ID + * @param controller Network controller's full fingerprint + * @return Pointer to C struct + */ + ZT_Certificate_Network* addSubjectNetwork(uint64_t id, const ZT_Fingerprint& controller); - /** - * Add an update URL to the updateUrls list - * - * @param url Update URL - */ - void addSubjectUpdateUrl(const char *url); + /** + * Add an update URL to the updateUrls list + * + * @param url Update URL + */ + void addSubjectUpdateUrl(const char* url); - /** - * Sign subject with unique ID private key and set. - * - * This is done when you createCSR but can also be done explicitly here. This - * is mostly for testing purposes. - * - * @param uniqueIdPrivate Unique ID private key (includes public) - * @param uniqueIdPrivateSize Size of private key - * @return True on success - */ - ZT_INLINE bool setSubjectUniqueId(const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) - { return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize); } + /** + * Sign subject with unique ID private key and set. + * + * This is done when you createCSR but can also be done explicitly here. This + * is mostly for testing purposes. + * + * @param uniqueIdPrivate Unique ID private key (includes public) + * @param uniqueIdPrivateSize Size of private key + * @return True on success + */ + ZT_INLINE bool setSubjectUniqueId(const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize) + { + return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize); + } - /** - * Marshal this certificate in binary form - * - * The internal encoding used here is Dictionary to permit easy - * extensibility. - * - * @param omitSignature If true omit the signature field (for signing and verification, default is false) - * @return Marshaled certificate - */ - Vector< uint8_t > encode(bool omitSignature = false) const; + /** + * Marshal this certificate in binary form + * + * The internal encoding used here is Dictionary to permit easy + * extensibility. + * + * @param omitSignature If true omit the signature field (for signing and verification, default is false) + * @return Marshaled certificate + */ + Vector encode(bool omitSignature = false) const; - /** - * Decode this certificate from marshaled bytes. - * - * @param data Marshalled certificate - * @param len Length of marshalled certificate - * @return True if input is valid and was unmarshalled (signature is NOT checked) - */ - bool decode(const void *data, unsigned int len); + /** + * Decode this certificate from marshaled bytes. + * + * @param data Marshalled certificate + * @param len Length of marshalled certificate + * @return True if input is valid and was unmarshalled (signature is NOT checked) + */ + bool decode(const void* data, unsigned int len); - /** - * Sign this certificate. - * - * This sets serialNo, issuer, issuerPublicKey, and signature. - * - * @return True on success - */ - bool sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *issuerPrivateKey, unsigned int issuerPrivateKeySize); + /** + * Sign this certificate. + * + * This sets serialNo, issuer, issuerPublicKey, and signature. + * + * @return True on success + */ + bool sign( + const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], + const void* issuerPrivateKey, + unsigned int issuerPrivateKeySize); - /** - * Verify self-contained signatures and validity of certificate structure - * - * This cannot check the chain of trust back to a CA, only the internal validity - * of this certificate. - * - * @param clock If non-negative, also do verifyTimeWindow() - * @param checkSignatures If true, perform full signature check (which is more expensive than other checks) - * @return OK (0) or error code indicating why certificate failed verification. - */ - ZT_CertificateError verify(int64_t clock, bool checkSignatures) const; + /** + * Verify self-contained signatures and validity of certificate structure + * + * This cannot check the chain of trust back to a CA, only the internal validity + * of this certificate. + * + * @param clock If non-negative, also do verifyTimeWindow() + * @param checkSignatures If true, perform full signature check (which is more expensive than other checks) + * @return OK (0) or error code indicating why certificate failed verification. + */ + ZT_CertificateError verify(int64_t clock, bool checkSignatures) const; - /** - * Check this certificate's expiration status - * - * @param clock Current real world time in milliseconds since epoch - * @return True if certificate is not expired or outside window - */ - ZT_INLINE bool verifyTimeWindow(int64_t clock) const noexcept - { return ((clock >= this->validity[0]) && (clock <= this->validity[1]) && (this->validity[0] <= this->validity[1])); } + /** + * Check this certificate's expiration status + * + * @param clock Current real world time in milliseconds since epoch + * @return True if certificate is not expired or outside window + */ + ZT_INLINE bool verifyTimeWindow(int64_t clock) const noexcept + { + return ( + (clock >= this->validity[0]) && (clock <= this->validity[1]) && (this->validity[0] <= this->validity[1])); + } - /** - * Create a new certificate public/private key pair - * - * @param type Key pair type to create - * @param publicKey Buffer to fill with public key - * @param publicKeySize Result parameter: set to size of public key - * @param privateKey Buffer to fill with private key - * @param privateKeySize Result parameter: set to size of private key - * @return True on success - */ - static bool newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize); + /** + * Create a new certificate public/private key pair + * + * @param type Key pair type to create + * @param publicKey Buffer to fill with public key + * @param publicKeySize Result parameter: set to size of public key + * @param privateKey Buffer to fill with private key + * @param privateKeySize Result parameter: set to size of private key + * @return True on success + */ + static bool newKeyPair( + const ZT_CertificatePublicKeyAlgorithm type, + uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], + int* const publicKeySize, + uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], + int* const privateKeySize); - /** - * Create a CSR that encodes the subject of this certificate - * - * @param s Subject to encode - * @param certificatePublicKey Public key for certificate - * @param certificatePublicKeySize Size of public key - * @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none - * @param uniqueIdPrivateSize Size of unique ID private key - * @return Encoded subject (without any unique ID fields) or empty vector on error - */ - static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *certificatePublicKey, unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize); + /** + * Create a CSR that encodes the subject of this certificate + * + * @param s Subject to encode + * @param certificatePublicKey Public key for certificate + * @param certificatePublicKeySize Size of public key + * @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none + * @param uniqueIdPrivateSize Size of unique ID private key + * @return Encoded subject (without any unique ID fields) or empty vector on error + */ + static Vector createCSR( + const ZT_Certificate_Subject& s, + const void* certificatePublicKey, + unsigned int certificatePublicKeySize, + const void* uniqueIdPrivate, + unsigned int uniqueIdPrivateSize); - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)Utils::loadMachineEndian< uint32_t >(this->serialNo); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)Utils::loadMachineEndian(this->serialNo); + } - ZT_INLINE bool operator==(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0; } + ZT_INLINE bool operator==(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0; + } - ZT_INLINE bool operator!=(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0; } + ZT_INLINE bool operator!=(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0; + } - ZT_INLINE bool operator<(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0; } + ZT_INLINE bool operator<(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0; + } - ZT_INLINE bool operator<=(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0; } + ZT_INLINE bool operator<=(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0; + } - ZT_INLINE bool operator>(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0; } + ZT_INLINE bool operator>(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0; + } - ZT_INLINE bool operator>=(const ZT_Certificate &c) const noexcept - { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; } + ZT_INLINE bool operator>=(const ZT_Certificate& c) const noexcept + { + return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; + } -private: - void m_clear(); - static bool m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize); - static void m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature); + private: + void m_clear(); + static bool + m_setSubjectUniqueId(ZT_Certificate_Subject& s, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize); + static void m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d, bool omitUniqueIdProofSignature); - // These hold any identity or locator objects that are owned by and should - // be deleted with this certificate. Lists are used so the pointers never - // change. - ForwardList< Identity > m_identities; - ForwardList< Locator > m_locators; - ForwardList< String > m_strings; + // These hold any identity or locator objects that are owned by and should + // be deleted with this certificate. Lists are used so the pointers never + // change. + ForwardList m_identities; + ForwardList m_locators; + ForwardList m_strings; - // These are stored in a vector because the memory needs to be contiguous. - Vector< ZT_Certificate_Identity > m_subjectIdentities; - Vector< ZT_Certificate_Network > m_subjectNetworks; - Vector< const char * > m_updateUrls; - Vector< uint8_t > m_extendedAttributes; + // These are stored in a vector because the memory needs to be contiguous. + Vector m_subjectIdentities; + Vector m_subjectNetworks; + Vector m_updateUrls; + Vector m_extendedAttributes; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Constants.hpp b/core/Constants.hpp index 2f0f861ab..3253dc250 100644 --- a/core/Constants.hpp +++ b/core/Constants.hpp @@ -20,8 +20,8 @@ #define ZT_CORE 1 #include "OS.hpp" -#include "zerotier.h" #include "version.h" +#include "zerotier.h" /** * Length of a ZeroTier address in bytes @@ -190,7 +190,8 @@ #define ZT_PEER_WHOIS_RATE_LIMIT 100 /** - * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound + * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and + * outbound */ #define ZT_PEER_GENERAL_RATE_LIMIT 500 @@ -209,7 +210,7 @@ /* Ethernet frame types that might be relevant to us */ #define ZT_ETHERTYPE_IPV4 0x0800 -#define ZT_ETHERTYPE_ARP 0x0806 +#define ZT_ETHERTYPE_ARP 0x0806 #define ZT_ETHERTYPE_IPV6 0x86dd #endif diff --git a/core/Containers.hpp b/core/Containers.hpp index 18cffee3d..e3be3ba77 100644 --- a/core/Containers.hpp +++ b/core/Containers.hpp @@ -19,111 +19,104 @@ #include "Constants.hpp" #include "Utils.hpp" -#include -#include +#include #include +#include #include #include -#include +#include #ifdef __CPP11__ #include -#include #include +#include #endif namespace ZeroTier { -template< typename V > -class Vector : public std::vector< V > -{ -public: - ZT_INLINE Vector() : - std::vector< V >() - {} +template class Vector : public std::vector { + public: + ZT_INLINE Vector() : std::vector() + { + } - template< typename I > - ZT_INLINE Vector(I begin, I end) : - std::vector< V >(begin, end) - {} + template ZT_INLINE Vector(I begin, I end) : std::vector(begin, end) + { + } }; -template< typename V > -class List : public std::list< V > -{ +template class List : public std::list { }; #ifdef __CPP11__ -struct intl_MapHasher -{ - template< typename O > - std::size_t operator()(const O &obj) const noexcept - { return (std::size_t)obj.hashCode(); } +struct intl_MapHasher { + template std::size_t operator()(const O& obj) const noexcept + { + return (std::size_t)obj.hashCode(); + } - std::size_t operator()(const Vector< uint8_t > &bytes) const noexcept - { return (std::size_t)Utils::fnv1a32(bytes.data(), (unsigned int)bytes.size()); } + std::size_t operator()(const Vector& bytes) const noexcept + { + return (std::size_t)Utils::fnv1a32(bytes.data(), (unsigned int)bytes.size()); + } - std::size_t operator()(const uint64_t i) const noexcept - { return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce); } + std::size_t operator()(const uint64_t i) const noexcept + { + return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce); + } - std::size_t operator()(const int64_t i) const noexcept - { return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce); } + std::size_t operator()(const int64_t i) const noexcept + { + return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce); + } - std::size_t operator()(const uint32_t i) const noexcept - { return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce); } + std::size_t operator()(const uint32_t i) const noexcept + { + return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce); + } - std::size_t operator()(const int32_t i) const noexcept - { return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce); } + std::size_t operator()(const int32_t i) const noexcept + { + return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce); + } }; -template< typename K, typename V > -class Map : public std::unordered_map< K, V, intl_MapHasher > -{ +template class Map : public std::unordered_map { }; -template< typename K, typename V > -class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K > > -{ +template +class MultiMap : public std::unordered_multimap > { }; #else -template -class Map : public std::map< K, V > -{}; +template class Map : public std::map { +}; -template -class MultiMap : public std::multimap< K, V > -{}; +template class MultiMap : public std::multimap { +}; #endif -template< typename K, typename V > -class SortedMap : public std::map< K, V > -{ +template class SortedMap : public std::map { }; #ifdef __CPP11__ -template< typename V > -class ForwardList : public std::forward_list< V > -{ +template class ForwardList : public std::forward_list { }; #else -template< typename V > -class ForwardList : public std::list< V > -{}; +template class ForwardList : public std::list { +}; #endif -template< typename V > -class Set : public std::set< V, std::less< V > > -{ +template class Set : public std::set > { }; typedef std::string String; @@ -131,48 +124,72 @@ typedef std::string String; /** * A 384-bit hash */ -struct H384 -{ - uint64_t data[6]; +struct H384 { + uint64_t data[6]; - ZT_INLINE H384() noexcept - { Utils::zero< sizeof(data) >(data); } + ZT_INLINE H384() noexcept + { + Utils::zero(data); + } - ZT_INLINE H384(const H384 &b) noexcept - { Utils::copy< 48 >(data, b.data); } + ZT_INLINE H384(const H384& b) noexcept + { + Utils::copy<48>(data, b.data); + } - explicit ZT_INLINE H384(const void *const d) noexcept - { Utils::copy< 48 >(data, d); } + explicit ZT_INLINE H384(const void* const d) noexcept + { + Utils::copy<48>(data, d); + } - ZT_INLINE H384 &operator=(const H384 &b) noexcept - { - Utils::copy< 48 >(data, b.data); - return *this; - } + ZT_INLINE H384& operator=(const H384& b) noexcept + { + Utils::copy<48>(data, b.data); + return *this; + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)data[0]; } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)data[0]; + } - ZT_INLINE operator bool() const noexcept - { return ((data[0] != 0) && (data[1] != 0) && (data[2] != 0) && (data[3] != 0) && (data[4] != 0) && (data[5] != 0)); } + ZT_INLINE operator bool() const noexcept + { + return ( + (data[0] != 0) && (data[1] != 0) && (data[2] != 0) && (data[3] != 0) && (data[4] != 0) && (data[5] != 0)); + } - ZT_INLINE bool operator==(const H384 &b) const noexcept - { return ((data[0] == b.data[0]) && (data[1] == b.data[1]) && (data[2] == b.data[2]) && (data[3] == b.data[3]) && (data[4] == b.data[4]) && (data[5] == b.data[5])); } + ZT_INLINE bool operator==(const H384& b) const noexcept + { + return ( + (data[0] == b.data[0]) && (data[1] == b.data[1]) && (data[2] == b.data[2]) && (data[3] == b.data[3]) + && (data[4] == b.data[4]) && (data[5] == b.data[5])); + } - ZT_INLINE bool operator!=(const H384 &b) const noexcept - { return !(*this == b); } + ZT_INLINE bool operator!=(const H384& b) const noexcept + { + return ! (*this == b); + } - ZT_INLINE bool operator<(const H384 &b) const noexcept - { return std::lexicographical_compare(data, data + 6, b.data, b.data + 6); } + ZT_INLINE bool operator<(const H384& b) const noexcept + { + return std::lexicographical_compare(data, data + 6, b.data, b.data + 6); + } - ZT_INLINE bool operator<=(const H384 &b) const noexcept - { return !(b < *this); } + ZT_INLINE bool operator<=(const H384& b) const noexcept + { + return ! (b < *this); + } - ZT_INLINE bool operator>(const H384 &b) const noexcept - { return (b < *this); } + ZT_INLINE bool operator>(const H384& b) const noexcept + { + return (b < *this); + } - ZT_INLINE bool operator>=(const H384 &b) const noexcept - { return !(*this < b); } + ZT_INLINE bool operator>=(const H384& b) const noexcept + { + return ! (*this < b); + } }; static_assert(sizeof(H384) == 48, "H384 contains unnecessary padding"); @@ -182,59 +199,79 @@ static_assert(sizeof(H384) == 48, "H384 contains unnecessary padding"); * * @tparam S Size in bytes */ -template< unsigned long S > -struct Blob -{ - uint8_t data[S]; +template struct Blob { + uint8_t data[S]; - ZT_INLINE Blob() noexcept - { Utils::zero< S >(data); } + ZT_INLINE Blob() noexcept + { + Utils::zero(data); + } - ZT_INLINE Blob(const Blob &b) noexcept - { Utils::copy< S >(data, b.data); } + ZT_INLINE Blob(const Blob& b) noexcept + { + Utils::copy(data, b.data); + } - explicit ZT_INLINE Blob(const void *const d) noexcept - { Utils::copy< S >(data, d); } + explicit ZT_INLINE Blob(const void* const d) noexcept + { + Utils::copy(data, d); + } - explicit ZT_INLINE Blob(const void *const d, const unsigned int l) noexcept - { - Utils::copy(data, d, (l > (unsigned int)S) ? (unsigned int)S : l); - if (l < S) { - Utils::zero(data + l, S - l); - } - } + explicit ZT_INLINE Blob(const void* const d, const unsigned int l) noexcept + { + Utils::copy(data, d, (l > (unsigned int)S) ? (unsigned int)S : l); + if (l < S) { + Utils::zero(data + l, S - l); + } + } - ZT_INLINE Blob &operator=(const Blob &b) noexcept - { - Utils::copy< S >(data, b.data); - return *this; - } + ZT_INLINE Blob& operator=(const Blob& b) noexcept + { + Utils::copy(data, b.data); + return *this; + } - ZT_INLINE unsigned long hashCode() const noexcept - { return Utils::fnv1a32(data, (unsigned int)S); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return Utils::fnv1a32(data, (unsigned int)S); + } - ZT_INLINE operator bool() const noexcept - { return Utils::allZero(data, (unsigned int)S); } + ZT_INLINE operator bool() const noexcept + { + return Utils::allZero(data, (unsigned int)S); + } - ZT_INLINE bool operator==(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) == 0); } + ZT_INLINE bool operator==(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) == 0); + } - ZT_INLINE bool operator!=(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) != 0); } + ZT_INLINE bool operator!=(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) != 0); + } - ZT_INLINE bool operator<(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) < 0); } + ZT_INLINE bool operator<(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) < 0); + } - ZT_INLINE bool operator<=(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) <= 0); } + ZT_INLINE bool operator<=(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) <= 0); + } - ZT_INLINE bool operator>(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) > 0); } + ZT_INLINE bool operator>(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) > 0); + } - ZT_INLINE bool operator>=(const Blob &b) const noexcept - { return (memcmp(data, b.data, S) >= 0); } + ZT_INLINE bool operator>=(const Blob& b) const noexcept + { + return (memcmp(data, b.data, S) >= 0); + } }; -} // ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Context.hpp b/core/Context.hpp index aa9678342..dacb8a79d 100644 --- a/core/Context.hpp +++ b/core/Context.hpp @@ -14,12 +14,12 @@ #ifndef ZT_RUNTIMEENVIRONMENT_HPP #define ZT_RUNTIMEENVIRONMENT_HPP -#include "Constants.hpp" -#include "Utils.hpp" -#include "Identity.hpp" #include "AES.hpp" -#include "TinyMap.hpp" +#include "Constants.hpp" +#include "Identity.hpp" #include "SharedPtr.hpp" +#include "TinyMap.hpp" +#include "Utils.hpp" namespace ZeroTier { @@ -38,68 +38,69 @@ class Network; /** * Node instance context */ -class Context -{ -public: - ZT_INLINE Context(Node *const n) noexcept: - instanceId(Utils::getSecureRandomU64()), - node(n), - uPtr(nullptr), - localNetworkController(nullptr), - store(nullptr), - networks(nullptr), - t(nullptr), - expect(nullptr), - vl2(nullptr), - vl1(nullptr), - topology(nullptr), - sa(nullptr), - ts(nullptr) - { - publicIdentityStr[0] = 0; - secretIdentityStr[0] = 0; - } +class Context { + public: + ZT_INLINE Context(Node* const n) noexcept + : instanceId(Utils::getSecureRandomU64()) + , node(n) + , uPtr(nullptr) + , localNetworkController(nullptr) + , store(nullptr) + , networks(nullptr) + , t(nullptr) + , expect(nullptr) + , vl2(nullptr) + , vl1(nullptr) + , topology(nullptr) + , sa(nullptr) + , ts(nullptr) + { + publicIdentityStr[0] = 0; + secretIdentityStr[0] = 0; + } - ZT_INLINE ~Context() noexcept - { Utils::burn(secretIdentityStr, sizeof(secretIdentityStr)); } + ZT_INLINE ~Context() noexcept + { + Utils::burn(secretIdentityStr, sizeof(secretIdentityStr)); + } - // Unique ID generated on startup - const uint64_t instanceId; + // Unique ID generated on startup + const uint64_t instanceId; - // Node instance that owns this RuntimeEnvironment - Node *const restrict node; + // Node instance that owns this RuntimeEnvironment + Node* const restrict node; - // Callbacks specified by caller who created node - ZT_Node_Callbacks cb; + // Callbacks specified by caller who created node + ZT_Node_Callbacks cb; - // User pointer specified by external code via API - void *restrict uPtr; + // User pointer specified by external code via API + void* restrict uPtr; - // This is set externally to an instance of this base class - NetworkController *restrict localNetworkController; + // This is set externally to an instance of this base class + NetworkController* restrict localNetworkController; - Store *restrict store; - TinyMap< SharedPtr< Network > > *restrict networks; - Trace *restrict t; - Expect *restrict expect; - VL2 *restrict vl2; - VL1 *restrict vl1; - Topology *restrict topology; - SelfAwareness *restrict sa; - TrustStore *restrict ts; + Store* restrict store; + TinyMap >* restrict networks; + Trace* restrict t; + Expect* restrict expect; + VL2* restrict vl2; + VL1* restrict vl1; + Topology* restrict topology; + SelfAwareness* restrict sa; + TrustStore* restrict ts; - // This node's identity and string representations thereof - Identity identity; - char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + // This node's identity and string representations thereof + Identity identity; + char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - // Symmetric key for encrypting secrets at rest on this system. - AES localSecretCipher; + // Symmetric key for encrypting secrets at rest on this system. + AES localSecretCipher; - // Privileged ports from 1 to 1023 in a random order (for IPv4 NAT traversal) - uint16_t randomPrivilegedPortOrder[1023]; + // Privileged ports from 1 to 1023 in a random order (for IPv4 NAT traversal) + uint16_t randomPrivilegedPortOrder[1023]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Credential.cpp b/core/Credential.cpp index 9f79d6ded..add933f2e 100644 --- a/core/Credential.cpp +++ b/core/Credential.cpp @@ -11,15 +11,16 @@ */ /****/ +#include "Credential.hpp" + +#include "CapabilityCredential.hpp" #include "Constants.hpp" #include "Context.hpp" -#include "Credential.hpp" -#include "CapabilityCredential.hpp" -#include "TagCredential.hpp" #include "MembershipCredential.hpp" +#include "Network.hpp" #include "OwnershipCredential.hpp" #include "RevocationCredential.hpp" -#include "Network.hpp" +#include "TagCredential.hpp" #include "Topology.hpp" // These are compile-time asserts to make sure temporary marshal buffers here and @@ -42,57 +43,77 @@ namespace ZeroTier { -template< typename CRED > -static ZT_INLINE Credential::VerifyResult p_credVerify(const Context &ctx, const CallContext &cc, CRED credential) +template +static ZT_INLINE Credential::VerifyResult p_credVerify(const Context& ctx, const CallContext& cc, CRED credential) { - uint8_t tmp[ZT_BUF_MEM_SIZE + 16]; + uint8_t tmp[ZT_BUF_MEM_SIZE + 16]; - const Address signedBy(credential.signer()); - const uint64_t networkId = credential.networkId(); - if ((!signedBy) || (signedBy != Network::controllerFor(networkId))) - return Credential::VERIFY_BAD_SIGNATURE; + const Address signedBy(credential.signer()); + const uint64_t networkId = credential.networkId(); + if ((! signedBy) || (signedBy != Network::controllerFor(networkId))) + return Credential::VERIFY_BAD_SIGNATURE; - const SharedPtr< Peer > peer(ctx.topology->peer(cc, signedBy)); - if (!peer) - return Credential::VERIFY_NEED_IDENTITY; + const SharedPtr peer(ctx.topology->peer(cc, signedBy)); + if (! peer) + return Credential::VERIFY_NEED_IDENTITY; - try { - int l = credential.marshal(tmp, true); - if (l <= 0) - return Credential::VERIFY_BAD_SIGNATURE; - return (peer->identity().verify(tmp, (unsigned int)l, credential.signature(), credential.signatureLength()) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE); - } catch (...) {} + try { + int l = credential.marshal(tmp, true); + if (l <= 0) + return Credential::VERIFY_BAD_SIGNATURE; + return ( + peer->identity().verify(tmp, (unsigned int)l, credential.signature(), credential.signatureLength()) + ? Credential::VERIFY_OK + : Credential::VERIFY_BAD_SIGNATURE); + } + catch (...) { + } - return Credential::VERIFY_BAD_SIGNATURE; + return Credential::VERIFY_BAD_SIGNATURE; } -Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const RevocationCredential &credential) -{ return p_credVerify(ctx, cc, credential); } - -Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const TagCredential &credential) -{ return p_credVerify(ctx, cc, credential); } - -Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const CapabilityCredential &credential) -{ return p_credVerify(ctx, cc, credential); } - -Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const OwnershipCredential &credential) -{ return p_credVerify(ctx, cc, credential); } - -Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const MembershipCredential &credential) +Credential::VerifyResult +Credential::s_verify(const Context& ctx, const CallContext& cc, const RevocationCredential& credential) { - // Sanity check network ID. - if ((!credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId))) - return Credential::VERIFY_BAD_SIGNATURE; - - // If we don't know the peer, get its identity. This shouldn't happen here but should be handled. - const SharedPtr< Peer > peer(ctx.topology->peer(cc, credential.m_signedBy)); - if (!peer) - return Credential::VERIFY_NEED_IDENTITY; - - // Now verify the controller's signature. - uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; - const unsigned int bufSize = credential.m_fillSigningBuf(buf); - return peer->identity().verify(buf, bufSize, credential.m_signature, credential.m_signatureLength) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE; + return p_credVerify(ctx, cc, credential); } -} // namespace ZeroTier +Credential::VerifyResult +Credential::s_verify(const Context& ctx, const CallContext& cc, const TagCredential& credential) +{ + return p_credVerify(ctx, cc, credential); +} + +Credential::VerifyResult +Credential::s_verify(const Context& ctx, const CallContext& cc, const CapabilityCredential& credential) +{ + return p_credVerify(ctx, cc, credential); +} + +Credential::VerifyResult +Credential::s_verify(const Context& ctx, const CallContext& cc, const OwnershipCredential& credential) +{ + return p_credVerify(ctx, cc, credential); +} + +Credential::VerifyResult +Credential::s_verify(const Context& ctx, const CallContext& cc, const MembershipCredential& credential) +{ + // Sanity check network ID. + if ((! credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId))) + return Credential::VERIFY_BAD_SIGNATURE; + + // If we don't know the peer, get its identity. This shouldn't happen here but should be handled. + const SharedPtr peer(ctx.topology->peer(cc, credential.m_signedBy)); + if (! peer) + return Credential::VERIFY_NEED_IDENTITY; + + // Now verify the controller's signature. + uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; + const unsigned int bufSize = credential.m_fillSigningBuf(buf); + return peer->identity().verify(buf, bufSize, credential.m_signature, credential.m_signatureLength) + ? Credential::VERIFY_OK + : Credential::VERIFY_BAD_SIGNATURE; +} + +} // namespace ZeroTier diff --git a/core/Credential.hpp b/core/Credential.hpp index e30a498dd..d3fc92185 100644 --- a/core/Credential.hpp +++ b/core/Credential.hpp @@ -14,9 +14,9 @@ #ifndef ZT_CREDENTIAL_HPP #define ZT_CREDENTIAL_HPP +#include "CallContext.hpp" #include "Constants.hpp" #include "TriviallyCopyable.hpp" -#include "CallContext.hpp" namespace ZeroTier { @@ -35,27 +35,21 @@ class Context; * All credential verification methods are implemented in Credential.cpp as they share a lot * of common code and logic and grouping them makes auditing easier. */ -class Credential : public TriviallyCopyable -{ -public: - /** - * Result of verify() operations - */ - enum VerifyResult - { - VERIFY_OK = 0, - VERIFY_BAD_SIGNATURE = 1, - VERIFY_NEED_IDENTITY = 2 - }; +class Credential : public TriviallyCopyable { + public: + /** + * Result of verify() operations + */ + enum VerifyResult { VERIFY_OK = 0, VERIFY_BAD_SIGNATURE = 1, VERIFY_NEED_IDENTITY = 2 }; -protected: - static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const MembershipCredential &credential); - static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const RevocationCredential &credential); - static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const TagCredential &credential); - static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const OwnershipCredential &credential); - static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const CapabilityCredential &credential); + protected: + static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const MembershipCredential& credential); + static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const RevocationCredential& credential); + static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const TagCredential& credential); + static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const OwnershipCredential& credential); + static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const CapabilityCredential& credential); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Defaults.cpp b/core/Defaults.cpp index 14c31f42b..7fd55d67f 100644 --- a/core/Defaults.cpp +++ b/core/Defaults.cpp @@ -16,9 +16,9 @@ namespace ZeroTier { namespace Defaults { -const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {}; +const uint8_t* CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {}; unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT] = {}; -} // namespace Defaults -} // namespace ZeroTier +} // namespace Defaults +} // namespace ZeroTier diff --git a/core/Defaults.hpp b/core/Defaults.hpp index 5cb239d94..d65e0b9d6 100644 --- a/core/Defaults.hpp +++ b/core/Defaults.hpp @@ -21,10 +21,10 @@ namespace Defaults { #define DEFAULT_CERTIFICATE_COUNT 0 -extern const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT]; +extern const uint8_t* CERTIFICATE[DEFAULT_CERTIFICATE_COUNT]; extern unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT]; -} // namespace Defaults -} // namespace ZeroTier +} // namespace Defaults +} // namespace ZeroTier #endif diff --git a/core/Defragmenter.hpp b/core/Defragmenter.hpp index e4c6994a9..27bb867de 100644 --- a/core/Defragmenter.hpp +++ b/core/Defragmenter.hpp @@ -14,13 +14,13 @@ #ifndef ZT_DEFRAGMENTER_HPP #define ZT_DEFRAGMENTER_HPP -#include "Constants.hpp" #include "Buf.hpp" -#include "SharedPtr.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "FCV.hpp" #include "Mutex.hpp" #include "Path.hpp" -#include "FCV.hpp" -#include "Containers.hpp" +#include "SharedPtr.hpp" namespace ZeroTier { @@ -40,318 +40,324 @@ namespace ZeroTier { * the ones used throughout the ZeroTier core. * * @tparam MF Maximum number of fragments that each message can possess (default: ZT_MAX_PACKET_FRAGMENTS) - * @tparam MFP Maximum number of incoming fragments per path (if paths are specified) (default: ZT_MAX_INCOMING_FRAGMENTS_PER_PATH) + * @tparam MFP Maximum number of incoming fragments per path (if paths are specified) (default: + * ZT_MAX_INCOMING_FRAGMENTS_PER_PATH) * @tparam GCS Garbage collection target size for the incoming message queue (default: ZT_MAX_PACKET_FRAGMENTS * 2) * @tparam GCT Garbage collection trigger threshold, usually 2X GCS (default: ZT_MAX_PACKET_FRAGMENTS * 4) * @tparam P Type for pointer to a path object (default: SharedPtr) */ -template< - unsigned int MF = ZT_MAX_PACKET_FRAGMENTS, - unsigned int MFP = ZT_MAX_INCOMING_FRAGMENTS_PER_PATH, - unsigned int GCS = (ZT_MAX_PACKET_FRAGMENTS * 2), - unsigned int GCT = (ZT_MAX_PACKET_FRAGMENTS * 4), - typename P = SharedPtr< Path > > -class Defragmenter -{ -public: - /** - * Return values from assemble() - */ - enum ResultCode - { - /** - * No error occurred, fragment accepted - */ - OK, +template < + unsigned int MF = ZT_MAX_PACKET_FRAGMENTS, + unsigned int MFP = ZT_MAX_INCOMING_FRAGMENTS_PER_PATH, + unsigned int GCS = (ZT_MAX_PACKET_FRAGMENTS * 2), + unsigned int GCT = (ZT_MAX_PACKET_FRAGMENTS * 4), + typename P = SharedPtr > +class Defragmenter { + public: + /** + * Return values from assemble() + */ + enum ResultCode { + /** + * No error occurred, fragment accepted + */ + OK, - /** - * Message fully assembled and placed in message vector - */ - COMPLETE, + /** + * Message fully assembled and placed in message vector + */ + COMPLETE, - /** - * We already have this fragment number or the message is complete - */ - ERR_DUPLICATE_FRAGMENT, + /** + * We already have this fragment number or the message is complete + */ + ERR_DUPLICATE_FRAGMENT, - /** - * The fragment is invalid, such as e.g. having a fragment number beyond the expected count. - */ - ERR_INVALID_FRAGMENT, + /** + * The fragment is invalid, such as e.g. having a fragment number beyond the expected count. + */ + ERR_INVALID_FRAGMENT, - /** - * Too many fragments are in flight for this path - * - * The message will be marked as if it's done (all fragments received) but will - * be abandoned. Subsequent fragments will generate a DUPLICATE_FRAGMENT error. - * - * This is an anti-denial-of-service feature to limit the number of inbound - * fragments that can be in flight over a given physical network path. - */ - ERR_TOO_MANY_FRAGMENTS_FOR_PATH, + /** + * Too many fragments are in flight for this path + * + * The message will be marked as if it's done (all fragments received) but will + * be abandoned. Subsequent fragments will generate a DUPLICATE_FRAGMENT error. + * + * This is an anti-denial-of-service feature to limit the number of inbound + * fragments that can be in flight over a given physical network path. + */ + ERR_TOO_MANY_FRAGMENTS_FOR_PATH, - /** - * Memory (or some other limit) exhausted - */ - ERR_OUT_OF_MEMORY - }; + /** + * Memory (or some other limit) exhausted + */ + ERR_OUT_OF_MEMORY + }; - ZT_INLINE Defragmenter() - {} + ZT_INLINE Defragmenter() + { + } - /** - * Process a fragment of a multi-part message - * - * The message ID is arbitrary but must be something that can uniquely - * group fragments for a given final message. The total fragments - * value is expected to be the same for all fragments in a message. Results - * are undefined and probably wrong if this value changes across a message. - * Fragment numbers must be sequential starting with 0 and going up to - * one minus total fragments expected (non-inclusive range). - * - * Fragments can arrive in any order. Duplicates are dropped and ignored. - * - * It's the responsibility of the caller to do whatever validation needs to - * be done before considering a fragment valid and to make sure the fragment - * data index and size parameters are valid. - * - * The fragment supplied to this function is kept and held under the supplied - * message ID until or unless (1) the message is fully assembled, (2) the - * message is orphaned and its entry is taken by a new message, or (3) the - * clear() function is called to forget all incoming messages. The pointer - * at the 'fragment' reference will be zeroed since this pointer is handed - * off, so the SharedPtr<> passed in as 'fragment' will be NULL after this - * function is called. - * - * The 'via' parameter causes this fragment to be registered with a path and - * unregistered when done or abandoned. It's only used the first time it's - * supplied (the first non-NULL) for a given message ID. This is a mitigation - * against memory exhausting DOS attacks. - * - * @tparam X Template parameter type for Buf<> containing fragment (inferred) - * @param messageId Message ID (a unique ID identifying this message) - * @param message Fixed capacity vector that will be filled with the result if result code is DONE - * @param fragment Buffer containing fragment that will be filed under this message's ID - * @param fragmentDataIndex Index of data in fragment's data.bytes (fragment's data.fields type is ignored) - * @param fragmentDataSize Length of data in fragment's data.bytes (fragment's data.fields type is ignored) - * @param fragmentNo Number of fragment (0..totalFragmentsExpected, non-inclusive) - * @param totalFragmentsExpected Total number of expected fragments in this message or 0 to use cached value - * @param ts Current time - * @param via If non-NULL this is the path on which this message fragment was received - * @return Result code - */ - ZT_INLINE ResultCode assemble( - const uint64_t messageId, - FCV< Buf::Slice, MF > &message, - SharedPtr< Buf > &fragment, - const unsigned int fragmentDataIndex, - const unsigned int fragmentDataSize, - const unsigned int fragmentNo, - const unsigned int totalFragmentsExpected, - const int64_t ts, - const P &via) - { - // Sanity checks for malformed fragments or invalid input parameters. - if ((fragmentNo >= totalFragmentsExpected) || (totalFragmentsExpected > MF) || (totalFragmentsExpected == 0)) - return ERR_INVALID_FRAGMENT; + /** + * Process a fragment of a multi-part message + * + * The message ID is arbitrary but must be something that can uniquely + * group fragments for a given final message. The total fragments + * value is expected to be the same for all fragments in a message. Results + * are undefined and probably wrong if this value changes across a message. + * Fragment numbers must be sequential starting with 0 and going up to + * one minus total fragments expected (non-inclusive range). + * + * Fragments can arrive in any order. Duplicates are dropped and ignored. + * + * It's the responsibility of the caller to do whatever validation needs to + * be done before considering a fragment valid and to make sure the fragment + * data index and size parameters are valid. + * + * The fragment supplied to this function is kept and held under the supplied + * message ID until or unless (1) the message is fully assembled, (2) the + * message is orphaned and its entry is taken by a new message, or (3) the + * clear() function is called to forget all incoming messages. The pointer + * at the 'fragment' reference will be zeroed since this pointer is handed + * off, so the SharedPtr<> passed in as 'fragment' will be NULL after this + * function is called. + * + * The 'via' parameter causes this fragment to be registered with a path and + * unregistered when done or abandoned. It's only used the first time it's + * supplied (the first non-NULL) for a given message ID. This is a mitigation + * against memory exhausting DOS attacks. + * + * @tparam X Template parameter type for Buf<> containing fragment (inferred) + * @param messageId Message ID (a unique ID identifying this message) + * @param message Fixed capacity vector that will be filled with the result if result code is DONE + * @param fragment Buffer containing fragment that will be filed under this message's ID + * @param fragmentDataIndex Index of data in fragment's data.bytes (fragment's data.fields type is ignored) + * @param fragmentDataSize Length of data in fragment's data.bytes (fragment's data.fields type is ignored) + * @param fragmentNo Number of fragment (0..totalFragmentsExpected, non-inclusive) + * @param totalFragmentsExpected Total number of expected fragments in this message or 0 to use cached value + * @param ts Current time + * @param via If non-NULL this is the path on which this message fragment was received + * @return Result code + */ + ZT_INLINE ResultCode assemble( + const uint64_t messageId, + FCV& message, + SharedPtr& fragment, + const unsigned int fragmentDataIndex, + const unsigned int fragmentDataSize, + const unsigned int fragmentNo, + const unsigned int totalFragmentsExpected, + const int64_t ts, + const P& via) + { + // Sanity checks for malformed fragments or invalid input parameters. + if ((fragmentNo >= totalFragmentsExpected) || (totalFragmentsExpected > MF) || (totalFragmentsExpected == 0)) + return ERR_INVALID_FRAGMENT; - // We hold the read lock on _messages unless we need to add a new entry or do GC. - RWMutex::RMaybeWLock ml(m_messages_l); + // We hold the read lock on _messages unless we need to add a new entry or do GC. + RWMutex::RMaybeWLock ml(m_messages_l); - // Check message hash table size and perform GC if necessary. - if (m_messages.size() >= GCT) { - try { - // Scan messages with read lock still locked first and make a sorted list of - // message entries by last modified time. Then lock for writing and delete - // the oldest entries to bring the size of the messages hash table down to - // under the target size. This tries to minimize the amount of time the write - // lock is held since many threads can hold the read lock but all threads must - // wait if someone holds the write lock. - std::vector< std::pair< int64_t, uint64_t > > messagesByLastUsedTime; - messagesByLastUsedTime.reserve(m_messages.size()); + // Check message hash table size and perform GC if necessary. + if (m_messages.size() >= GCT) { + try { + // Scan messages with read lock still locked first and make a sorted list of + // message entries by last modified time. Then lock for writing and delete + // the oldest entries to bring the size of the messages hash table down to + // under the target size. This tries to minimize the amount of time the write + // lock is held since many threads can hold the read lock but all threads must + // wait if someone holds the write lock. + std::vector > messagesByLastUsedTime; + messagesByLastUsedTime.reserve(m_messages.size()); - for (typename Map< uint64_t, p_E >::const_iterator i(m_messages.begin()); i != m_messages.end(); ++i) - messagesByLastUsedTime.push_back(std::pair< int64_t, uint64_t >(i->second.lastUsed, i->first)); - std::sort(messagesByLastUsedTime.begin(), messagesByLastUsedTime.end()); + for (typename Map::const_iterator i(m_messages.begin()); i != m_messages.end(); ++i) + messagesByLastUsedTime.push_back(std::pair(i->second.lastUsed, i->first)); + std::sort(messagesByLastUsedTime.begin(), messagesByLastUsedTime.end()); - ml.writing(); // acquire write lock on _messages - for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS); x <= y; ++x) - m_messages.erase(messagesByLastUsedTime[x].second); - } catch (...) { - return ERR_OUT_OF_MEMORY; - } - } + ml.writing(); // acquire write lock on _messages + for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS); x <= y; ++x) + m_messages.erase(messagesByLastUsedTime[x].second); + } + catch (...) { + return ERR_OUT_OF_MEMORY; + } + } - // Get or create message fragment. - Defragmenter< MF, MFP, GCS, GCT, P >::p_E *e; - { - typename Map< uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E >::iterator ee(m_messages.find(messageId)); - if (ee == m_messages.end()) { - ml.writing(); // acquire write lock on _messages if not already - try { - e = &(m_messages[messageId]); - } catch (...) { - return ERR_OUT_OF_MEMORY; - } - e->id = messageId; - } else { - e = &(ee->second); - } - } + // Get or create message fragment. + Defragmenter::p_E* e; + { + typename Map::p_E>::iterator ee(m_messages.find(messageId)); + if (ee == m_messages.end()) { + ml.writing(); // acquire write lock on _messages if not already + try { + e = &(m_messages[messageId]); + } + catch (...) { + return ERR_OUT_OF_MEMORY; + } + e->id = messageId; + } + else { + e = &(ee->second); + } + } - // Switch back to holding only the read lock on _messages if we have locked for write - ml.reading(); + // Switch back to holding only the read lock on _messages if we have locked for write + ml.reading(); - // Acquire lock on entry itself - Mutex::Lock el(e->lock); + // Acquire lock on entry itself + Mutex::Lock el(e->lock); - // This magic value means this message has already been assembled and is done. - if (e->lastUsed < 0) - return ERR_DUPLICATE_FRAGMENT; + // This magic value means this message has already been assembled and is done. + if (e->lastUsed < 0) + return ERR_DUPLICATE_FRAGMENT; - // Update last-activity timestamp for this entry, delaying GC. - e->lastUsed = ts; + // Update last-activity timestamp for this entry, delaying GC. + e->lastUsed = ts; - // Learn total fragments expected if a value is given. Otherwise the cached - // value gets used. This is to support the implementation of fragmentation - // in the ZT protocol where only fragments carry the total. - if (totalFragmentsExpected > 0) - e->totalFragmentsExpected = totalFragmentsExpected; + // Learn total fragments expected if a value is given. Otherwise the cached + // value gets used. This is to support the implementation of fragmentation + // in the ZT protocol where only fragments carry the total. + if (totalFragmentsExpected > 0) + e->totalFragmentsExpected = totalFragmentsExpected; - // If there is a path associated with this fragment make sure we've registered - // ourselves as in flight, check the limit, and abort if exceeded. - if ((via) && (!e->via)) { - e->via = via; - bool tooManyPerPath = false; - via->m_inboundFragmentedMessages_l.lock(); - try { - if (via->m_inboundFragmentedMessages.size() < MFP) { - via->m_inboundFragmentedMessages.insert(messageId); - } else { - tooManyPerPath = true; - } - } catch (...) { - // This would indicate something like bad_alloc thrown by the set. Treat - // it as limit exceeded. - tooManyPerPath = true; - } - via->m_inboundFragmentedMessages_l.unlock(); - if (tooManyPerPath) - return ERR_TOO_MANY_FRAGMENTS_FOR_PATH; - } + // If there is a path associated with this fragment make sure we've registered + // ourselves as in flight, check the limit, and abort if exceeded. + if ((via) && (! e->via)) { + e->via = via; + bool tooManyPerPath = false; + via->m_inboundFragmentedMessages_l.lock(); + try { + if (via->m_inboundFragmentedMessages.size() < MFP) { + via->m_inboundFragmentedMessages.insert(messageId); + } + else { + tooManyPerPath = true; + } + } + catch (...) { + // This would indicate something like bad_alloc thrown by the set. Treat + // it as limit exceeded. + tooManyPerPath = true; + } + via->m_inboundFragmentedMessages_l.unlock(); + if (tooManyPerPath) + return ERR_TOO_MANY_FRAGMENTS_FOR_PATH; + } - // If we already have fragment number X, abort. Note that we do not - // actually compare data here. Two same-numbered fragments with different - // data would just mean the transfer is corrupt and would be detected - // later e.g. by packet MAC check. Other use cases of this code like - // network configs check each fragment so this basically can't happen. - Buf::Slice &s = e->message.at(fragmentNo); - if (s.b) - return ERR_DUPLICATE_FRAGMENT; + // If we already have fragment number X, abort. Note that we do not + // actually compare data here. Two same-numbered fragments with different + // data would just mean the transfer is corrupt and would be detected + // later e.g. by packet MAC check. Other use cases of this code like + // network configs check each fragment so this basically can't happen. + Buf::Slice& s = e->message.at(fragmentNo); + if (s.b) + return ERR_DUPLICATE_FRAGMENT; - // Take ownership of fragment, setting 'fragment' pointer to NULL. The simple - // transfer of the pointer avoids a synchronized increment/decrement of the object's - // reference count. - s.b.move(fragment); - s.s = fragmentDataIndex; - s.e = fragmentDataIndex + fragmentDataSize; - ++e->fragmentsReceived; + // Take ownership of fragment, setting 'fragment' pointer to NULL. The simple + // transfer of the pointer avoids a synchronized increment/decrement of the object's + // reference count. + s.b.move(fragment); + s.s = fragmentDataIndex; + s.e = fragmentDataIndex + fragmentDataSize; + ++e->fragmentsReceived; - // If we now have all fragments then assemble them. - if ((e->fragmentsReceived >= e->totalFragmentsExpected) && (e->totalFragmentsExpected > 0)) { - // This message is done so de-register it with its path if one is associated. - if (e->via) { - e->via->m_inboundFragmentedMessages_l.lock(); - e->via->m_inboundFragmentedMessages.erase(messageId); - e->via->m_inboundFragmentedMessages_l.unlock(); - e->via.zero(); - } + // If we now have all fragments then assemble them. + if ((e->fragmentsReceived >= e->totalFragmentsExpected) && (e->totalFragmentsExpected > 0)) { + // This message is done so de-register it with its path if one is associated. + if (e->via) { + e->via->m_inboundFragmentedMessages_l.lock(); + e->via->m_inboundFragmentedMessages.erase(messageId); + e->via->m_inboundFragmentedMessages_l.unlock(); + e->via.zero(); + } - // Slices are TriviallyCopyable and so may be raw copied from e->message to - // the result parameter. This is fast. - e->message.unsafeMoveTo(message); - e->lastUsed = -1; // mark as "done" and force GC to collect + // Slices are TriviallyCopyable and so may be raw copied from e->message to + // the result parameter. This is fast. + e->message.unsafeMoveTo(message); + e->lastUsed = -1; // mark as "done" and force GC to collect - return COMPLETE; - } + return COMPLETE; + } - return OK; - } + return OK; + } - /** - * Erase all message entries in the internal queue - */ - ZT_INLINE void clear() - { - RWMutex::Lock ml(m_messages_l); - m_messages.clear(); - } + /** + * Erase all message entries in the internal queue + */ + ZT_INLINE void clear() + { + RWMutex::Lock ml(m_messages_l); + m_messages.clear(); + } - /** - * @return Number of entries currently in message defragmentation cache - */ - ZT_INLINE unsigned int cacheSize() noexcept - { - RWMutex::RLock ml(m_messages_l); - return m_messages.size(); - } + /** + * @return Number of entries currently in message defragmentation cache + */ + ZT_INLINE unsigned int cacheSize() noexcept + { + RWMutex::RLock ml(m_messages_l); + return m_messages.size(); + } -private: - // p_E is an entry in the message queue. - struct p_E - { - ZT_INLINE p_E() noexcept: - id(0), - lastUsed(0), - totalFragmentsExpected(0), - fragmentsReceived(0) - {} + private: + // p_E is an entry in the message queue. + struct p_E { + ZT_INLINE p_E() noexcept + : id(0) + , lastUsed(0) + , totalFragmentsExpected(0) + , fragmentsReceived(0) + { + } - ZT_INLINE p_E(const p_E &e) noexcept: - id(e.id), - lastUsed(e.lastUsed), - totalFragmentsExpected(e.totalFragmentsExpected), - fragmentsReceived(e.fragmentsReceived), - via(e.via), - message(e.message), - lock() - {} + ZT_INLINE p_E(const p_E& e) noexcept + : id(e.id) + , lastUsed(e.lastUsed) + , totalFragmentsExpected(e.totalFragmentsExpected) + , fragmentsReceived(e.fragmentsReceived) + , via(e.via) + , message(e.message) + , lock() + { + } - ZT_INLINE ~p_E() - { - if (via) { - via->m_inboundFragmentedMessages_l.lock(); - via->m_inboundFragmentedMessages.erase(id); - via->m_inboundFragmentedMessages_l.unlock(); - } - } + ZT_INLINE ~p_E() + { + if (via) { + via->m_inboundFragmentedMessages_l.lock(); + via->m_inboundFragmentedMessages.erase(id); + via->m_inboundFragmentedMessages_l.unlock(); + } + } - ZT_INLINE p_E &operator=(const p_E &e) - { - if (this != &e) { - id = e.id; - lastUsed = e.lastUsed; - totalFragmentsExpected = e.totalFragmentsExpected; - fragmentsReceived = e.fragmentsReceived; - via = e.via; - message = e.message; - } - return *this; - } + ZT_INLINE p_E& operator=(const p_E& e) + { + if (this != &e) { + id = e.id; + lastUsed = e.lastUsed; + totalFragmentsExpected = e.totalFragmentsExpected; + fragmentsReceived = e.fragmentsReceived; + via = e.via; + message = e.message; + } + return *this; + } - uint64_t id; - int64_t lastUsed; - unsigned int totalFragmentsExpected; - unsigned int fragmentsReceived; - P via; - FCV< Buf::Slice, MF > message; - Mutex lock; - }; + uint64_t id; + int64_t lastUsed; + unsigned int totalFragmentsExpected; + unsigned int fragmentsReceived; + P via; + FCV message; + Mutex lock; + }; - Map< uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E > m_messages; - RWMutex m_messages_l; + Map::p_E> m_messages; + RWMutex m_messages_l; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Dictionary.cpp b/core/Dictionary.cpp index d43689f93..e27cc11bf 100644 --- a/core/Dictionary.cpp +++ b/core/Dictionary.cpp @@ -15,157 +15,168 @@ namespace ZeroTier { -Vector< uint8_t > &Dictionary::operator[](const char *const k) -{ return m_entries[k]; } - -const Vector< uint8_t > &Dictionary::operator[](const char *const k) const +Vector& Dictionary::operator[](const char* const k) { - static const Vector< uint8_t > s_emptyEntry; - const SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(k)); - return (e == m_entries.end()) ? s_emptyEntry : e->second; + return m_entries[k]; } -void Dictionary::add(const char *k, const Address &v) +const Vector& Dictionary::operator[](const char* const k) const { - char tmp[ZT_ADDRESS_STRING_SIZE_MAX]; - v.toString(tmp); - add(k, tmp); + static const Vector s_emptyEntry; + const SortedMap >::const_iterator e(m_entries.find(k)); + return (e == m_entries.end()) ? s_emptyEntry : e->second; } -void Dictionary::add(const char *k, const char *v) +void Dictionary::add(const char* k, const Address& v) { - Vector< uint8_t > &e = (*this)[k]; - e.clear(); - if (v) { - while (*v) - e.push_back((uint8_t)*(v++)); - } + char tmp[ZT_ADDRESS_STRING_SIZE_MAX]; + v.toString(tmp); + add(k, tmp); } -void Dictionary::add(const char *k, const void *data, unsigned int len) +void Dictionary::add(const char* k, const char* v) { - Vector< uint8_t > &e = (*this)[k]; - if (likely(len != 0)) { - e.assign((const uint8_t *)data, (const uint8_t *)data + len); - } else { - e.clear(); - } + Vector& e = (*this)[k]; + e.clear(); + if (v) { + while (*v) + e.push_back((uint8_t) * (v++)); + } } -uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const +void Dictionary::add(const char* k, const void* data, unsigned int len) { - char tmp[32]; - getS(k, tmp, sizeof(tmp)); - if (tmp[0]) - return Utils::unhex(tmp); - return dfl; + Vector& e = (*this)[k]; + if (likely(len != 0)) { + e.assign((const uint8_t*)data, (const uint8_t*)data + len); + } + else { + e.clear(); + } } -char *Dictionary::getS(const char *k, char *v, const unsigned int cap) const +uint64_t Dictionary::getUI(const char* k, uint64_t dfl) const { - if (cap == 0) // sanity check - return v; + char tmp[32]; + getS(k, tmp, sizeof(tmp)); + if (tmp[0]) + return Utils::unhex(tmp); + return dfl; +} - const Vector< uint8_t > &e = (*this)[k]; - if (e.empty()) { - v[0] = 0; - return v; - } +char* Dictionary::getS(const char* k, char* v, const unsigned int cap) const +{ + if (cap == 0) // sanity check + return v; - for (unsigned int i = 0, last = (cap - 1);; ++i) { - if ((i >= last) || (i >= (unsigned int)e.size())) { - v[i] = 0; - break; - } - if ((v[i] = (char)e[i]) == 0) - break; - } + const Vector& e = (*this)[k]; + if (e.empty()) { + v[0] = 0; + return v; + } - return v; + for (unsigned int i = 0, last = (cap - 1);; ++i) { + if ((i >= last) || (i >= (unsigned int)e.size())) { + v[i] = 0; + break; + } + if ((v[i] = (char)e[i]) == 0) + break; + } + + return v; } void Dictionary::clear() -{ m_entries.clear(); } - -void Dictionary::encode(Vector< uint8_t > &out) const { - out.clear(); - for (SortedMap< String, Vector< uint8_t > >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) { - s_appendKey(out, ti->first.data()); - for (Vector< uint8_t >::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i) - s_appendValueByte(out, *i); - out.push_back((uint8_t)'\n'); - } + m_entries.clear(); } -bool Dictionary::decode(const void *data, unsigned int len) +void Dictionary::encode(Vector& out) const { - clear(); - String k; - Vector< uint8_t > *v = nullptr; - bool escape = false; - for (unsigned int di = 0; di < len; ++di) { - const uint8_t c = reinterpret_cast(data)[di]; - if (c) { - if (v) { - if (escape) { - escape = false; - switch (c) { - case 48: - v->push_back(0); - break; - case 101: - v->push_back(61); - break; - case 110: - v->push_back(10); - break; - case 114: - v->push_back(13); - break; - default: - v->push_back(c); - break; - } - } else { - if (c == (uint8_t)'\n') { - k.clear(); - v = nullptr; - } else if (c == 92) { // backslash - escape = true; - } else { - v->push_back(c); - } - } - } else { - if (c == (uint8_t)'=') { - v = &m_entries[k]; - } else { - k.push_back(c); - } - } - } else { - break; - } - } - return true; + out.clear(); + for (SortedMap >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) { + s_appendKey(out, ti->first.data()); + for (Vector::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i) + s_appendValueByte(out, *i); + out.push_back((uint8_t)'\n'); + } } -char *Dictionary::arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept +bool Dictionary::decode(const void* data, unsigned int len) { - if (bufSize < 17) { // sanity check - buf[0] = 0; - return buf; - } - for (unsigned int i = 0; i < (bufSize - 17); ++i) { - if ((buf[i] = name[i]) == 0) { - buf[i++] = '#'; - Utils::hex(sub, buf + i); - return buf; - } - } - buf[0] = 0; - return buf; + clear(); + String k; + Vector* v = nullptr; + bool escape = false; + for (unsigned int di = 0; di < len; ++di) { + const uint8_t c = reinterpret_cast(data)[di]; + if (c) { + if (v) { + if (escape) { + escape = false; + switch (c) { + case 48: + v->push_back(0); + break; + case 101: + v->push_back(61); + break; + case 110: + v->push_back(10); + break; + case 114: + v->push_back(13); + break; + default: + v->push_back(c); + break; + } + } + else { + if (c == (uint8_t)'\n') { + k.clear(); + v = nullptr; + } + else if (c == 92) { // backslash + escape = true; + } + else { + v->push_back(c); + } + } + } + else { + if (c == (uint8_t)'=') { + v = &m_entries[k]; + } + else { + k.push_back(c); + } + } + } + else { + break; + } + } + return true; } -} // namespace ZeroTier +char* Dictionary::arraySubscript(char* buf, unsigned int bufSize, const char* name, const unsigned long sub) noexcept +{ + if (bufSize < 17) { // sanity check + buf[0] = 0; + return buf; + } + for (unsigned int i = 0; i < (bufSize - 17); ++i) { + if ((buf[i] = name[i]) == 0) { + buf[i++] = '#'; + Utils::hex(sub, buf + i); + return buf; + } + } + buf[0] = 0; + return buf; +} + +} // namespace ZeroTier diff --git a/core/Dictionary.hpp b/core/Dictionary.hpp index 9db887e9c..c55d0a73a 100644 --- a/core/Dictionary.hpp +++ b/core/Dictionary.hpp @@ -14,11 +14,11 @@ #ifndef ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP -#include "Constants.hpp" -#include "Utils.hpp" #include "Address.hpp" #include "Buf.hpp" +#include "Constants.hpp" #include "Containers.hpp" +#include "Utils.hpp" namespace ZeroTier { @@ -37,420 +37,428 @@ class Identity; * The fastest way to build a dictionary to send is to use the append * static functions, not to populate and then encode a Dictionary. */ -class Dictionary -{ -public: - typedef SortedMap< String, Vector< uint8_t > >::const_iterator const_iterator; +class Dictionary { + public: + typedef SortedMap >::const_iterator const_iterator; - ZT_INLINE Dictionary() - {} + ZT_INLINE Dictionary() + { + } - ZT_INLINE ~Dictionary() - {} + ZT_INLINE ~Dictionary() + { + } - /* - ZT_INLINE void dump() const - { - printf("\n--\n"); - for (const_iterator e(begin()); e != end(); ++e) { - printf("%.8x %s=", Utils::fnv1a32(e->second.data(), (unsigned int)e->second.size()), e->first.c_str()); - bool binary = false; - for (Vector< uint8_t >::const_iterator c(e->second.begin()); c != e->second.end(); ++c) { - if ((*c < 33) || (*c > 126)) { - binary = true; - break; - } - } - if (binary) { - for (Vector< uint8_t >::const_iterator c(e->second.begin()); c != e->second.end(); ++c) - printf("%.2x", (unsigned int)*c); - } else { - Vector< uint8_t > s(e->second); - s.push_back(0); - printf("%s", s.data()); - } - printf("\n"); - } - printf("--\n"); - } - */ + /* + ZT_INLINE void dump() const + { + printf("\n--\n"); + for (const_iterator e(begin()); e != end(); ++e) { + printf("%.8x %s=", Utils::fnv1a32(e->second.data(), (unsigned int)e->second.size()), e->first.c_str()); + bool binary = false; + for (Vector< uint8_t >::const_iterator c(e->second.begin()); c != e->second.end(); ++c) { + if ((*c < 33) || (*c > 126)) { + binary = true; + break; + } + } + if (binary) { + for (Vector< uint8_t >::const_iterator c(e->second.begin()); c != e->second.end(); ++c) + printf("%.2x", (unsigned int)*c); + } else { + Vector< uint8_t > s(e->second); + s.push_back(0); + printf("%s", s.data()); + } + printf("\n"); + } + printf("--\n"); + } + */ - /** - * Get a reference to a value - * - * @param k Key to look up - * @return Reference to value - */ - Vector< uint8_t > &operator[](const char *k); + /** + * Get a reference to a value + * + * @param k Key to look up + * @return Reference to value + */ + Vector& operator[](const char* k); - /** - * Get a const reference to a value - * - * @param k Key to look up - * @return Reference to value or to empty vector if not found - */ - const Vector< uint8_t > &operator[](const char *k) const; + /** + * Get a const reference to a value + * + * @param k Key to look up + * @return Reference to value or to empty vector if not found + */ + const Vector& operator[](const char* k) const; - /** - * @return Start of key->value pairs - */ - ZT_INLINE const_iterator begin() const noexcept - { return m_entries.begin(); } + /** + * @return Start of key->value pairs + */ + ZT_INLINE const_iterator begin() const noexcept + { + return m_entries.begin(); + } - /** - * @return End of key->value pairs - */ - ZT_INLINE const_iterator end() const noexcept - { return m_entries.end(); } + /** + * @return End of key->value pairs + */ + ZT_INLINE const_iterator end() const noexcept + { + return m_entries.end(); + } - /** - * Add an integer as a hexadecimal string value - * - * @param k Key to set - * @param v Integer to set, will be cast to uint64_t and stored as hex - */ - ZT_INLINE void add(const char *const k, const uint64_t v) - { - char buf[24]; - add(k, Utils::hex((uint64_t)(v), buf)); - } + /** + * Add an integer as a hexadecimal string value + * + * @param k Key to set + * @param v Integer to set, will be cast to uint64_t and stored as hex + */ + ZT_INLINE void add(const char* const k, const uint64_t v) + { + char buf[24]; + add(k, Utils::hex((uint64_t)(v), buf)); + } - /** - * Add an integer as a hexadecimal string value - * - * @param k Key to set - * @param v Integer to set, will be cast to uint64_t and stored as hex - */ - ZT_INLINE void add(const char *const k, const int64_t v) - { - char buf[24]; - add(k, Utils::hex((uint64_t)(v), buf)); - } + /** + * Add an integer as a hexadecimal string value + * + * @param k Key to set + * @param v Integer to set, will be cast to uint64_t and stored as hex + */ + ZT_INLINE void add(const char* const k, const int64_t v) + { + char buf[24]; + add(k, Utils::hex((uint64_t)(v), buf)); + } - /** - * Add an address in 10-digit hex string format - */ - void add(const char *k, const Address &v); + /** + * Add an address in 10-digit hex string format + */ + void add(const char* k, const Address& v); - /** - * Add a C string as a value - */ - void add(const char *k, const char *v); + /** + * Add a C string as a value + */ + void add(const char* k, const char* v); - /** - * Add a binary blob as a value - */ - void add(const char *k, const void *data, unsigned int len); + /** + * Add a binary blob as a value + */ + void add(const char* k, const void* data, unsigned int len); - /** - * Get an integer - * - * @param k Key to look up - * @param dfl Default value (default: 0) - * @return Value of key or default if not found - */ - uint64_t getUI(const char *k, uint64_t dfl = 0) const; + /** + * Get an integer + * + * @param k Key to look up + * @param dfl Default value (default: 0) + * @return Value of key or default if not found + */ + uint64_t getUI(const char* k, uint64_t dfl = 0) const; - /** - * Get a C string - * - * If the buffer is too small the string will be truncated, but the - * buffer will always end in a terminating null no matter what. - * - * @param k Key to look up - * @param v Buffer to hold string - * @param cap Maximum size of string (including terminating null) - */ - char *getS(const char *k, char *v, unsigned int cap) const; + /** + * Get a C string + * + * If the buffer is too small the string will be truncated, but the + * buffer will always end in a terminating null no matter what. + * + * @param k Key to look up + * @param v Buffer to hold string + * @param cap Maximum size of string (including terminating null) + */ + char* getS(const char* k, char* v, unsigned int cap) const; - /** - * Get an object supporting the marshal/unmarshal interface pattern - * - * @tparam T Object type (inferred) - * @param k Key to look up - * @param obj Object to unmarshal() into - * @return True if unmarshal was successful - */ - template< typename T > - ZT_INLINE bool getO(const char *k, T &obj) const - { - const Vector< uint8_t > &d = (*this)[k]; - if (d.empty()) - return false; - return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0); - } + /** + * Get an object supporting the marshal/unmarshal interface pattern + * + * @tparam T Object type (inferred) + * @param k Key to look up + * @param obj Object to unmarshal() into + * @return True if unmarshal was successful + */ + template ZT_INLINE bool getO(const char* k, T& obj) const + { + const Vector& d = (*this)[k]; + if (d.empty()) + return false; + return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0); + } - /** - * Add an object supporting the marshal/unmarshal interface pattern - * - * @tparam T Object type (inferred) - * @param k Key to add - * @param obj Object to marshal() into vector - * @return True if successful - */ - template< typename T > - ZT_INLINE bool addO(const char *k, T &obj) - { - Vector< uint8_t > &d = (*this)[k]; - d.resize(T::marshalSizeMax()); - const int l = obj.marshal(d.data()); - if (l > 0) { - d.resize(l); - return true; - } - d.clear(); - return false; - } + /** + * Add an object supporting the marshal/unmarshal interface pattern + * + * @tparam T Object type (inferred) + * @param k Key to add + * @param obj Object to marshal() into vector + * @return True if successful + */ + template ZT_INLINE bool addO(const char* k, T& obj) + { + Vector& d = (*this)[k]; + d.resize(T::marshalSizeMax()); + const int l = obj.marshal(d.data()); + if (l > 0) { + d.resize(l); + return true; + } + d.clear(); + return false; + } - /** - * Erase all entries in dictionary - */ - void clear(); + /** + * Erase all entries in dictionary + */ + void clear(); - /** - * @return Number of entries - */ - ZT_INLINE unsigned int size() const noexcept - { return (unsigned int)m_entries.size(); } + /** + * @return Number of entries + */ + ZT_INLINE unsigned int size() const noexcept + { + return (unsigned int)m_entries.size(); + } - /** - * @return True if dictionary is not empty - */ - ZT_INLINE bool empty() const noexcept - { return m_entries.empty(); } + /** + * @return True if dictionary is not empty + */ + ZT_INLINE bool empty() const noexcept + { + return m_entries.empty(); + } - /** - * Encode to a string in the supplied vector - * - * @param out String encoded dictionary - */ - void encode(Vector< uint8_t > &out) const; + /** + * Encode to a string in the supplied vector + * + * @param out String encoded dictionary + */ + void encode(Vector& out) const; - /** - * Decode a string encoded dictionary - * - * This will decode up to 'len' but will also abort if it finds a - * null/zero as this could be a C string. - * - * @param data Data to decode - * @param len Length of data - * @return True if dictionary was formatted correctly and valid, false on error - */ - bool decode(const void *data, unsigned int len); + /** + * Decode a string encoded dictionary + * + * This will decode up to 'len' but will also abort if it finds a + * null/zero as this could be a C string. + * + * @param data Data to decode + * @param len Length of data + * @return True if dictionary was formatted correctly and valid, false on error + */ + bool decode(const void* data, unsigned int len); - /** - * Append a key=value pair to a buffer (vector or FCV) - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Value - */ - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const bool v) - { - s_appendKey(out, k); - out.push_back((uint8_t)(v ? '1' : '0')); - out.push_back((uint8_t)'\n'); - } + /** + * Append a key=value pair to a buffer (vector or FCV) + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Value + */ + template ZT_INLINE static void append(V& out, const char* const k, const bool v) + { + s_appendKey(out, k); + out.push_back((uint8_t)(v ? '1' : '0')); + out.push_back((uint8_t)'\n'); + } - /** - * Append a key=value pair to a buffer (vector or FCV) - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Value - */ - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const Address v) - { - s_appendKey(out, k); - const uint64_t a = v.toInt(); - static_assert(ZT_ADDRESS_LENGTH_HEX == 10, "this must be rewritten for any change in address length"); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 36U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 32U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 28U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 24U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 20U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 16U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 12U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 8U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[(a >> 4U) & 0xfU]); - out.push_back((uint8_t)Utils::HEXCHARS[a & 0xfU]); - out.push_back((uint8_t)'\n'); - } + /** + * Append a key=value pair to a buffer (vector or FCV) + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Value + */ + template ZT_INLINE static void append(V& out, const char* const k, const Address v) + { + s_appendKey(out, k); + const uint64_t a = v.toInt(); + static_assert(ZT_ADDRESS_LENGTH_HEX == 10, "this must be rewritten for any change in address length"); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 36U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 32U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 28U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 24U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 20U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 16U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 12U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 8U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[(a >> 4U) & 0xfU]); + out.push_back((uint8_t)Utils::HEXCHARS[a & 0xfU]); + out.push_back((uint8_t)'\n'); + } - /** - * Append a key=value pair to a buffer (vector or FCV) - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Value - */ - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const uint64_t v) - { - s_appendKey(out, k); - char buf[17]; - Utils::hex(v, buf); - unsigned int i = 0; - while (buf[i]) - out.push_back((uint8_t)buf[i++]); - out.push_back((uint8_t)'\n'); - } + /** + * Append a key=value pair to a buffer (vector or FCV) + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Value + */ + template ZT_INLINE static void append(V& out, const char* const k, const uint64_t v) + { + s_appendKey(out, k); + char buf[17]; + Utils::hex(v, buf); + unsigned int i = 0; + while (buf[i]) + out.push_back((uint8_t)buf[i++]); + out.push_back((uint8_t)'\n'); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const int64_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const int64_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const uint32_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const uint32_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const int32_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const int32_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const uint16_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const uint16_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const int16_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const int16_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const uint8_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const uint8_t v) + { + append(out, k, (uint64_t)v); + } - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const int8_t v) - { append(out, k, (uint64_t)v); } + template ZT_INLINE static void append(V& out, const char* const k, const int8_t v) + { + append(out, k, (uint64_t)v); + } - /** - * Append a key=value pair to a buffer (vector or FCV) - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Value - */ - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const char *v) - { - if ((v) && (*v)) { - s_appendKey(out, k); - while (*v) - s_appendValueByte(out, (uint8_t)*(v++)); - out.push_back((uint8_t)'\n'); - } - } + /** + * Append a key=value pair to a buffer (vector or FCV) + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Value + */ + template ZT_INLINE static void append(V& out, const char* const k, const char* v) + { + if ((v) && (*v)) { + s_appendKey(out, k); + while (*v) + s_appendValueByte(out, (uint8_t) * (v++)); + out.push_back((uint8_t)'\n'); + } + } - /** - * Append a key=value pair to a buffer (vector or FCV) - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Value - * @param vlen Value length in bytes - */ - template< typename V > - ZT_INLINE static void append(V &out, const char *const k, const void *const v, const unsigned int vlen) - { - s_appendKey(out, k); - for (unsigned int i = 0; i < vlen; ++i) - s_appendValueByte(out, reinterpret_cast(v)[i]); - out.push_back((uint8_t)'\n'); - } + /** + * Append a key=value pair to a buffer (vector or FCV) + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Value + * @param vlen Value length in bytes + */ + template + ZT_INLINE static void append(V& out, const char* const k, const void* const v, const unsigned int vlen) + { + s_appendKey(out, k); + for (unsigned int i = 0; i < vlen; ++i) + s_appendValueByte(out, reinterpret_cast(v)[i]); + out.push_back((uint8_t)'\n'); + } - /** - * Append a packet ID as raw bytes in the provided byte order - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param pid Packet ID - */ - template< typename V > - static ZT_INLINE void appendPacketId(V &out, const char *const k, const uint64_t pid) - { append(out, k, &pid, 8); } + /** + * Append a packet ID as raw bytes in the provided byte order + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param pid Packet ID + */ + template static ZT_INLINE void appendPacketId(V& out, const char* const k, const uint64_t pid) + { + append(out, k, &pid, 8); + } - /** - * Append key=value with any object implementing the correct marshal interface - * - * @param out Buffer - * @param k Key (must be <= 8 characters) - * @param v Marshal-able object - * @return Bytes appended or negative on error (return value of marshal()) - */ - template< typename V, typename T > - static ZT_INLINE int appendObject(V &out, const char *const k, const T &v) - { - uint8_t tmp[2048]; // large enough for any current object - if (T::marshalSizeMax() > sizeof(tmp)) - return -1; - const int mlen = v.marshal(tmp); - if (mlen > 0) - append(out, k, tmp, (unsigned int)mlen); - return mlen; - } + /** + * Append key=value with any object implementing the correct marshal interface + * + * @param out Buffer + * @param k Key (must be <= 8 characters) + * @param v Marshal-able object + * @return Bytes appended or negative on error (return value of marshal()) + */ + template static ZT_INLINE int appendObject(V& out, const char* const k, const T& v) + { + uint8_t tmp[2048]; // large enough for any current object + if (T::marshalSizeMax() > sizeof(tmp)) + return -1; + const int mlen = v.marshal(tmp); + if (mlen > 0) + append(out, k, tmp, (unsigned int)mlen); + return mlen; + } - /** - * Append #sub where sub is a hexadecimal string to 'name' and store in 'buf' - * - * @param buf Buffer to store subscript key - * @param name Root name - * @param sub Subscript index - * @return Pointer to 'buf' - */ - static char *arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept; + /** + * Append #sub where sub is a hexadecimal string to 'name' and store in 'buf' + * + * @param buf Buffer to store subscript key + * @param name Root name + * @param sub Subscript index + * @return Pointer to 'buf' + */ + static char* arraySubscript(char* buf, unsigned int bufSize, const char* name, const unsigned long sub) noexcept; -private: - template< typename V > - ZT_INLINE static void s_appendValueByte(V &out, const uint8_t c) - { - switch (c) { - case 0: - out.push_back(92); - out.push_back(48); - break; - case 10: - out.push_back(92); - out.push_back(110); - break; - case 13: - out.push_back(92); - out.push_back(114); - break; - case 61: - out.push_back(92); - out.push_back(101); - break; - case 92: - out.push_back(92); - out.push_back(92); - break; - default: - out.push_back(c); - break; - } - } + private: + template ZT_INLINE static void s_appendValueByte(V& out, const uint8_t c) + { + switch (c) { + case 0: + out.push_back(92); + out.push_back(48); + break; + case 10: + out.push_back(92); + out.push_back(110); + break; + case 13: + out.push_back(92); + out.push_back(114); + break; + case 61: + out.push_back(92); + out.push_back(101); + break; + case 92: + out.push_back(92); + out.push_back(92); + break; + default: + out.push_back(c); + break; + } + } - template< typename V > - ZT_INLINE static void s_appendKey(V &out, const char *k) - { - for (;;) { - const char c = *(k++); - if (c == 0) - break; - out.push_back((uint8_t)c); - } - out.push_back((uint8_t)'='); - } + template ZT_INLINE static void s_appendKey(V& out, const char* k) + { + for (;;) { + const char c = *(k++); + if (c == 0) + break; + out.push_back((uint8_t)c); + } + out.push_back((uint8_t)'='); + } - // Dictionary maps need to be sorted so that they always encode in the same order - // to yield blobs that can be hashed and signed reproducibly. Other than for areas - // where dictionaries are signed and verified the order doesn't matter. - SortedMap< String, Vector< uint8_t > > m_entries; + // Dictionary maps need to be sorted so that they always encode in the same order + // to yield blobs that can be hashed and signed reproducibly. Other than for areas + // where dictionaries are signed and verified the order doesn't matter. + SortedMap > m_entries; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/ECC384.cpp b/core/ECC384.cpp index 15cb0d38a..8eaff50a8 100644 --- a/core/ECC384.cpp +++ b/core/ECC384.cpp @@ -2,942 +2,992 @@ // https://github.com/esxgx/easy-ecc // This code is under the BSD 2-clause license, not ZeroTier's license -#include "Constants.hpp" #include "ECC384.hpp" + +#include "Constants.hpp" #include "Utils.hpp" namespace ZeroTier { namespace { -#define uint unsigned int -#define secp384r1 48 -#define ECC_CURVE secp384r1 -#define ECC_BYTES ECC_CURVE -#define NUM_ECC_DIGITS (ECC_BYTES/8) +#define uint unsigned int +#define secp384r1 48 +#define ECC_CURVE secp384r1 +#define ECC_BYTES ECC_CURVE +#define NUM_ECC_DIGITS (ECC_BYTES / 8) #define ECC_CREATE_KEY_MAX_ATTEMPTS 1024 #ifdef ZT_HAVE_UINT128 #define SUPPORTS_INT128 1 #else #define SUPPORTS_INT128 0 -typedef struct -{ - uint64_t m_low; - uint64_t m_high; +typedef struct { + uint64_t m_low; + uint64_t m_high; } uint128_t; #endif -typedef struct EccPoint -{ - uint64_t x[NUM_ECC_DIGITS]; - uint64_t y[NUM_ECC_DIGITS]; +typedef struct EccPoint { + uint64_t x[NUM_ECC_DIGITS]; + uint64_t y[NUM_ECC_DIGITS]; } EccPoint; #define CONCAT1(a, b) a##b -#define CONCAT(a, b) CONCAT1(a, b) -#define Curve_P_48 {0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF} -#define Curve_B_48 {0x2A85C8EDD3EC2AEF, 0xC656398D8A2ED19D, 0x0314088F5013875A, 0x181D9C6EFE814112, 0x988E056BE3F82D19, 0xB3312FA7E23EE7E4} -#define Curve_G_48 {{0x3A545E3872760AB7, 0x5502F25DBF55296C, 0x59F741E082542A38, 0x6E1D3B628BA79B98, 0x8EB1C71EF320AD74, 0xAA87CA22BE8B0537}, {0x7A431D7C90EA0E5F, 0x0A60B1CE1D7E819D, 0xE9DA3113B5F0B8C0, 0xF8F41DBD289A147C, 0x5D9E98BF9292DC29, 0x3617DE4A96262C6F}} -#define Curve_N_48 {0xECEC196ACCC52973, 0x581A0DB248B0A77A, 0xC7634D81F4372DDF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF} +#define CONCAT(a, b) CONCAT1(a, b) +#define Curve_P_48 \ + { \ + 0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, \ + 0xFFFFFFFFFFFFFFFF \ + } +#define Curve_B_48 \ + { \ + 0x2A85C8EDD3EC2AEF, 0xC656398D8A2ED19D, 0x0314088F5013875A, 0x181D9C6EFE814112, 0x988E056BE3F82D19, \ + 0xB3312FA7E23EE7E4 \ + } +#define Curve_G_48 \ + { \ + { 0x3A545E3872760AB7, 0x5502F25DBF55296C, 0x59F741E082542A38, \ + 0x6E1D3B628BA79B98, 0x8EB1C71EF320AD74, 0xAA87CA22BE8B0537 }, \ + { \ + 0x7A431D7C90EA0E5F, 0x0A60B1CE1D7E819D, 0xE9DA3113B5F0B8C0, 0xF8F41DBD289A147C, 0x5D9E98BF9292DC29, \ + 0x3617DE4A96262C6F \ + } \ + } +#define Curve_N_48 \ + { \ + 0xECEC196ACCC52973, 0x581A0DB248B0A77A, 0xC7634D81F4372DDF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, \ + 0xFFFFFFFFFFFFFFFF \ + } const uint64_t curve_p[NUM_ECC_DIGITS] = CONCAT(Curve_P_, ECC_CURVE); const uint64_t curve_b[NUM_ECC_DIGITS] = CONCAT(Curve_B_, ECC_CURVE); const EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE); const uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE); -ZT_INLINE int getRandomNumber(uint64_t *p_vli) +ZT_INLINE int getRandomNumber(uint64_t* p_vli) { - Utils::getSecureRandom(p_vli, ECC_BYTES); - return 1; + Utils::getSecureRandom(p_vli, ECC_BYTES); + return 1; } -ZT_INLINE void vli_clear(uint64_t *p_vli) -{ Utils::zero< sizeof(uint64_t) * NUM_ECC_DIGITS >(p_vli); } - -ZT_INLINE int vli_isZero(const uint64_t *p_vli) +ZT_INLINE void vli_clear(uint64_t* p_vli) { - uint i; - for (i = 0; i < NUM_ECC_DIGITS; ++i) { - if (p_vli[i]) - return 0; - } - return 1; + Utils::zero(p_vli); } -ZT_INLINE uint64_t vli_testBit(const uint64_t *p_vli, uint p_bit) -{ return (p_vli[p_bit / 64] & ((uint64_t)1 << (p_bit % 64))); } - -ZT_INLINE uint vli_numDigits(const uint64_t *p_vli) +ZT_INLINE int vli_isZero(const uint64_t* p_vli) { - int i; - for (i = NUM_ECC_DIGITS - 1; i >= 0 && p_vli[i] == 0; --i) {} - return (uint)(i + 1); + uint i; + for (i = 0; i < NUM_ECC_DIGITS; ++i) { + if (p_vli[i]) + return 0; + } + return 1; } -ZT_INLINE uint vli_numBits(const uint64_t *p_vli) +ZT_INLINE uint64_t vli_testBit(const uint64_t* p_vli, uint p_bit) { - uint i; - uint64_t l_digit; - - uint l_numDigits = vli_numDigits(p_vli); - if (l_numDigits == 0) { - return 0; - } - - l_digit = p_vli[l_numDigits - 1]; - for (i = 0; l_digit; ++i) { - l_digit >>= 1; - } - - return ((l_numDigits - 1) * 64 + i); + return (p_vli[p_bit / 64] & ((uint64_t)1 << (p_bit % 64))); } -ZT_INLINE void vli_set(uint64_t *p_dest, const uint64_t *p_src) +ZT_INLINE uint vli_numDigits(const uint64_t* p_vli) { - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) - p_dest[i] = p_src[i]; + int i; + for (i = NUM_ECC_DIGITS - 1; i >= 0 && p_vli[i] == 0; --i) {} + return (uint)(i + 1); } -ZT_INLINE int vli_cmp(const uint64_t *p_left, const uint64_t *p_right) +ZT_INLINE uint vli_numBits(const uint64_t* p_vli) { - for (int i = NUM_ECC_DIGITS - 1; i >= 0; --i) { - if (p_left[i] > p_right[i]) { - return 1; - } else if (p_left[i] < p_right[i]) { - return -1; - } - } - return 0; + uint i; + uint64_t l_digit; + + uint l_numDigits = vli_numDigits(p_vli); + if (l_numDigits == 0) { + return 0; + } + + l_digit = p_vli[l_numDigits - 1]; + for (i = 0; l_digit; ++i) { + l_digit >>= 1; + } + + return ((l_numDigits - 1) * 64 + i); } -ZT_INLINE uint64_t vli_lshift(uint64_t *p_result, const uint64_t *p_in, uint p_shift) +ZT_INLINE void vli_set(uint64_t* p_dest, const uint64_t* p_src) { - uint64_t l_carry = 0; - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { - uint64_t l_temp = p_in[i]; - p_result[i] = (l_temp << p_shift) | l_carry; - l_carry = l_temp >> (64 - p_shift); - } - return l_carry; + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) + p_dest[i] = p_src[i]; } -ZT_INLINE void vli_rshift1(uint64_t *p_vli) +ZT_INLINE int vli_cmp(const uint64_t* p_left, const uint64_t* p_right) { - uint64_t *l_end = p_vli; - uint64_t l_carry = 0; - p_vli += NUM_ECC_DIGITS; - while (p_vli-- > l_end) { - uint64_t l_temp = *p_vli; - *p_vli = (l_temp >> 1) | l_carry; - l_carry = l_temp << 63; - } + for (int i = NUM_ECC_DIGITS - 1; i >= 0; --i) { + if (p_left[i] > p_right[i]) { + return 1; + } + else if (p_left[i] < p_right[i]) { + return -1; + } + } + return 0; } -ZT_INLINE uint64_t vli_add(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) +ZT_INLINE uint64_t vli_lshift(uint64_t* p_result, const uint64_t* p_in, uint p_shift) { - uint64_t l_carry = 0; - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { - uint64_t l_sum = p_left[i] + p_right[i] + l_carry; - if (l_sum != p_left[i]) { - l_carry = (l_sum < p_left[i]); - } - p_result[i] = l_sum; - } - return l_carry; + uint64_t l_carry = 0; + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { + uint64_t l_temp = p_in[i]; + p_result[i] = (l_temp << p_shift) | l_carry; + l_carry = l_temp >> (64 - p_shift); + } + return l_carry; } -ZT_INLINE uint64_t vli_sub(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) +ZT_INLINE void vli_rshift1(uint64_t* p_vli) { - uint64_t l_borrow = 0; - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { - uint64_t l_diff = p_left[i] - p_right[i] - l_borrow; - if (l_diff != p_left[i]) { - l_borrow = (l_diff > p_left[i]); - } - p_result[i] = l_diff; - } - return l_borrow; + uint64_t* l_end = p_vli; + uint64_t l_carry = 0; + p_vli += NUM_ECC_DIGITS; + while (p_vli-- > l_end) { + uint64_t l_temp = *p_vli; + *p_vli = (l_temp >> 1) | l_carry; + l_carry = l_temp << 63; + } +} + +ZT_INLINE uint64_t vli_add(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right) +{ + uint64_t l_carry = 0; + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { + uint64_t l_sum = p_left[i] + p_right[i] + l_carry; + if (l_sum != p_left[i]) { + l_carry = (l_sum < p_left[i]); + } + p_result[i] = l_sum; + } + return l_carry; +} + +ZT_INLINE uint64_t vli_sub(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right) +{ + uint64_t l_borrow = 0; + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { + uint64_t l_diff = p_left[i] - p_right[i] - l_borrow; + if (l_diff != p_left[i]) { + l_borrow = (l_diff > p_left[i]); + } + p_result[i] = l_diff; + } + return l_borrow; } #if SUPPORTS_INT128 == 1 -void vli_mult(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) +void vli_mult(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right) { - uint128_t r01 = 0; - uint64_t r2 = 0; + uint128_t r01 = 0; + uint64_t r2 = 0; - uint i, k; + uint i, k; - for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { - uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); - for (i = l_min; i <= k && i < NUM_ECC_DIGITS; ++i) { - uint128_t l_product = (uint128_t)p_left[i] * p_right[k - i]; - r01 += l_product; - r2 += (r01 < l_product); - } - p_result[k] = (uint64_t)r01; - r01 = (r01 >> 64U) | (((uint128_t)r2) << 64U); - r2 = 0; - } + for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { + uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); + for (i = l_min; i <= k && i < NUM_ECC_DIGITS; ++i) { + uint128_t l_product = (uint128_t)p_left[i] * p_right[k - i]; + r01 += l_product; + r2 += (r01 < l_product); + } + p_result[k] = (uint64_t)r01; + r01 = (r01 >> 64U) | (((uint128_t)r2) << 64U); + r2 = 0; + } - p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01; + p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01; } -void vli_square(uint64_t *p_result, const uint64_t *p_left) +void vli_square(uint64_t* p_result, const uint64_t* p_left) { - uint128_t r01 = 0; - uint64_t r2 = 0; + uint128_t r01 = 0; + uint64_t r2 = 0; - uint i, k; - for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { - uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); - for (i = l_min; i <= k && i <= k - i; ++i) { - uint128_t l_product = (uint128_t)p_left[i] * p_left[k - i]; - if (i < k - i) { - r2 += l_product >> 127; - l_product *= 2; - } - r01 += l_product; - r2 += (r01 < l_product); - } - p_result[k] = (uint64_t)r01; - r01 = (r01 >> 64) | (((uint128_t)r2) << 64); - r2 = 0; - } + uint i, k; + for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { + uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); + for (i = l_min; i <= k && i <= k - i; ++i) { + uint128_t l_product = (uint128_t)p_left[i] * p_left[k - i]; + if (i < k - i) { + r2 += l_product >> 127; + l_product *= 2; + } + r01 += l_product; + r2 += (r01 < l_product); + } + p_result[k] = (uint64_t)r01; + r01 = (r01 >> 64) | (((uint128_t)r2) << 64); + r2 = 0; + } - p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01; + p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01; } #else /* #if SUPPORTS_INT128 */ uint128_t mul_64_64(uint64_t p_left, uint64_t p_right) { - uint128_t l_result; + uint128_t l_result; - uint64_t a0 = p_left & 0xffffffffull; - uint64_t a1 = p_left >> 32; - uint64_t b0 = p_right & 0xffffffffull; - uint64_t b1 = p_right >> 32; + uint64_t a0 = p_left & 0xffffffffull; + uint64_t a1 = p_left >> 32; + uint64_t b0 = p_right & 0xffffffffull; + uint64_t b1 = p_right >> 32; - uint64_t m0 = a0 * b0; - uint64_t m1 = a0 * b1; - uint64_t m2 = a1 * b0; - uint64_t m3 = a1 * b1; + uint64_t m0 = a0 * b0; + uint64_t m1 = a0 * b1; + uint64_t m2 = a1 * b0; + uint64_t m3 = a1 * b1; - m2 += (m0 >> 32); - m2 += m1; - if (m2 < m1) { // overflow - m3 += 0x100000000ull; - } + m2 += (m0 >> 32); + m2 += m1; + if (m2 < m1) { // overflow + m3 += 0x100000000ull; + } - l_result.m_low = (m0 & 0xffffffffull) | (m2 << 32); - l_result.m_high = m3 + (m2 >> 32); + l_result.m_low = (m0 & 0xffffffffull) | (m2 << 32); + l_result.m_high = m3 + (m2 >> 32); - return l_result; + return l_result; } ZT_INLINE uint128_t add_128_128(uint128_t a, uint128_t b) { - uint128_t l_result; - l_result.m_low = a.m_low + b.m_low; - l_result.m_high = a.m_high + b.m_high + (l_result.m_low < a.m_low); - return l_result; + uint128_t l_result; + l_result.m_low = a.m_low + b.m_low; + l_result.m_high = a.m_high + b.m_high + (l_result.m_low < a.m_low); + return l_result; } -void vli_mult(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right) +void vli_mult(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right) { - uint128_t r01 = {0, 0}; - uint64_t r2 = 0; + uint128_t r01 = { 0, 0 }; + uint64_t r2 = 0; - uint i, k; + uint i, k; - /* Compute each digit of p_result in sequence, maintaining the carries. */ - for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { - uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); - for (i = l_min; i <= k && i < NUM_ECC_DIGITS; ++i) { - uint128_t l_product = mul_64_64(p_left[i], p_right[k - i]); - r01 = add_128_128(r01, l_product); - r2 += (r01.m_high < l_product.m_high); - } - p_result[k] = r01.m_low; - r01.m_low = r01.m_high; - r01.m_high = r2; - r2 = 0; - } + /* Compute each digit of p_result in sequence, maintaining the carries. */ + for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { + uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); + for (i = l_min; i <= k && i < NUM_ECC_DIGITS; ++i) { + uint128_t l_product = mul_64_64(p_left[i], p_right[k - i]); + r01 = add_128_128(r01, l_product); + r2 += (r01.m_high < l_product.m_high); + } + p_result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } - p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low; + p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low; } -void vli_square(uint64_t *p_result, uint64_t *p_left) +void vli_square(uint64_t* p_result, uint64_t* p_left) { - uint128_t r01 = {0, 0}; - uint64_t r2 = 0; + uint128_t r01 = { 0, 0 }; + uint64_t r2 = 0; - uint i, k; - for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { - uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); - for (i = l_min; i <= k && i <= k - i; ++i) { - uint128_t l_product = mul_64_64(p_left[i], p_left[k - i]); - if (i < k - i) { - r2 += l_product.m_high >> 63; - l_product.m_high = (l_product.m_high << 1) | (l_product.m_low >> 63); - l_product.m_low <<= 1; - } - r01 = add_128_128(r01, l_product); - r2 += (r01.m_high < l_product.m_high); - } - p_result[k] = r01.m_low; - r01.m_low = r01.m_high; - r01.m_high = r2; - r2 = 0; - } + uint i, k; + for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { + uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); + for (i = l_min; i <= k && i <= k - i; ++i) { + uint128_t l_product = mul_64_64(p_left[i], p_left[k - i]); + if (i < k - i) { + r2 += l_product.m_high >> 63; + l_product.m_high = (l_product.m_high << 1) | (l_product.m_low >> 63); + l_product.m_low <<= 1; + } + r01 = add_128_128(r01, l_product); + r2 += (r01.m_high < l_product.m_high); + } + p_result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } - p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low; + p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low; } #endif /* SUPPORTS_INT128 */ -void vli_modAdd(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, const uint64_t *p_mod) +void vli_modAdd(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right, const uint64_t* p_mod) { - uint64_t l_carry = vli_add(p_result, p_left, p_right); - if (l_carry || vli_cmp(p_result, p_mod) >= 0) { - vli_sub(p_result, p_result, p_mod); - } + uint64_t l_carry = vli_add(p_result, p_left, p_right); + if (l_carry || vli_cmp(p_result, p_mod) >= 0) { + vli_sub(p_result, p_result, p_mod); + } } -void vli_modSub(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, const uint64_t *p_mod) +void vli_modSub(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right, const uint64_t* p_mod) { - uint64_t l_borrow = vli_sub(p_result, p_left, p_right); - if (l_borrow) { - vli_add(p_result, p_result, p_mod); - } + uint64_t l_borrow = vli_sub(p_result, p_left, p_right); + if (l_borrow) { + vli_add(p_result, p_result, p_mod); + } } -void omega_mult(uint64_t *p_result, uint64_t *p_right) +void omega_mult(uint64_t* p_result, uint64_t* p_right) { - uint64_t l_tmp[NUM_ECC_DIGITS]; - uint64_t l_carry, l_diff; + uint64_t l_tmp[NUM_ECC_DIGITS]; + uint64_t l_carry, l_diff; - vli_set(p_result, p_right); - l_carry = vli_lshift(l_tmp, p_right, 32); - p_result[1 + NUM_ECC_DIGITS] = l_carry + vli_add(p_result + 1, p_result + 1, l_tmp); - p_result[2 + NUM_ECC_DIGITS] = vli_add(p_result + 2, p_result + 2, p_right); - l_carry += vli_sub(p_result, p_result, l_tmp); - l_diff = p_result[NUM_ECC_DIGITS] - l_carry; - if (l_diff > p_result[NUM_ECC_DIGITS]) { - uint i; - for (i = 1 + NUM_ECC_DIGITS;; ++i) { - --p_result[i]; - if (p_result[i] != (uint64_t)-1) { - break; - } - } - } - p_result[NUM_ECC_DIGITS] = l_diff; + vli_set(p_result, p_right); + l_carry = vli_lshift(l_tmp, p_right, 32); + p_result[1 + NUM_ECC_DIGITS] = l_carry + vli_add(p_result + 1, p_result + 1, l_tmp); + p_result[2 + NUM_ECC_DIGITS] = vli_add(p_result + 2, p_result + 2, p_right); + l_carry += vli_sub(p_result, p_result, l_tmp); + l_diff = p_result[NUM_ECC_DIGITS] - l_carry; + if (l_diff > p_result[NUM_ECC_DIGITS]) { + uint i; + for (i = 1 + NUM_ECC_DIGITS;; ++i) { + --p_result[i]; + if (p_result[i] != (uint64_t)-1) { + break; + } + } + } + p_result[NUM_ECC_DIGITS] = l_diff; } -void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) +void vli_mmod_fast(uint64_t* p_result, uint64_t* p_product) { - uint64_t l_tmp[2 * NUM_ECC_DIGITS]; + uint64_t l_tmp[2 * NUM_ECC_DIGITS]; - while (!vli_isZero(p_product + NUM_ECC_DIGITS)) { - uint64_t l_carry = 0; - uint i; + while (! vli_isZero(p_product + NUM_ECC_DIGITS)) { + uint64_t l_carry = 0; + uint i; - vli_clear(l_tmp); - vli_clear(l_tmp + NUM_ECC_DIGITS); - omega_mult(l_tmp, p_product + NUM_ECC_DIGITS); - vli_clear(p_product + NUM_ECC_DIGITS); + vli_clear(l_tmp); + vli_clear(l_tmp + NUM_ECC_DIGITS); + omega_mult(l_tmp, p_product + NUM_ECC_DIGITS); + vli_clear(p_product + NUM_ECC_DIGITS); - for (i = 0; i < NUM_ECC_DIGITS + 3; ++i) { - uint64_t l_sum = p_product[i] + l_tmp[i] + l_carry; - if (l_sum != p_product[i]) { - l_carry = (l_sum < p_product[i]); - } - p_product[i] = l_sum; - } - } + for (i = 0; i < NUM_ECC_DIGITS + 3; ++i) { + uint64_t l_sum = p_product[i] + l_tmp[i] + l_carry; + if (l_sum != p_product[i]) { + l_carry = (l_sum < p_product[i]); + } + p_product[i] = l_sum; + } + } - while (vli_cmp(p_product, curve_p) > 0) { - vli_sub(p_product, p_product, curve_p); - } - vli_set(p_result, p_product); + while (vli_cmp(p_product, curve_p) > 0) { + vli_sub(p_product, p_product, curve_p); + } + vli_set(p_result, p_product); } -ZT_INLINE void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right) +ZT_INLINE void vli_modMult_fast(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right) { - uint64_t l_product[2 * NUM_ECC_DIGITS]; - vli_mult(l_product, p_left, p_right); - vli_mmod_fast(p_result, l_product); + uint64_t l_product[2 * NUM_ECC_DIGITS]; + vli_mult(l_product, p_left, p_right); + vli_mmod_fast(p_result, l_product); } -ZT_INLINE void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left) +ZT_INLINE void vli_modSquare_fast(uint64_t* p_result, uint64_t* p_left) { - uint64_t l_product[2 * NUM_ECC_DIGITS]; - vli_square(l_product, p_left); - vli_mmod_fast(p_result, l_product); + uint64_t l_product[2 * NUM_ECC_DIGITS]; + vli_square(l_product, p_left); + vli_mmod_fast(p_result, l_product); } -#define vli_isEven(vli) (!(vli[0] & 1)) +#define vli_isEven(vli) (! (vli[0] & 1)) /* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size. See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */ -void vli_modInv(uint64_t *p_result, uint64_t *p_input, const uint64_t *p_mod) +void vli_modInv(uint64_t* p_result, uint64_t* p_input, const uint64_t* p_mod) { - uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; - uint64_t l_carry; - int l_cmpResult; + uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; + uint64_t l_carry; + int l_cmpResult; - if (vli_isZero(p_input)) { - vli_clear(p_result); - return; - } + if (vli_isZero(p_input)) { + vli_clear(p_result); + return; + } - vli_set(a, p_input); - vli_set(b, p_mod); - vli_clear(u); - u[0] = 1; - vli_clear(v); + vli_set(a, p_input); + vli_set(b, p_mod); + vli_clear(u); + u[0] = 1; + vli_clear(v); - while ((l_cmpResult = vli_cmp(a, b)) != 0) { - l_carry = 0; - if (vli_isEven(a)) { - vli_rshift1(a); - if (!vli_isEven(u)) { - l_carry = vli_add(u, u, p_mod); - } - vli_rshift1(u); - if (l_carry) { - u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; - } - } else if (vli_isEven(b)) { - vli_rshift1(b); - if (!vli_isEven(v)) { - l_carry = vli_add(v, v, p_mod); - } - vli_rshift1(v); - if (l_carry) { - v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; - } - } else if (l_cmpResult > 0) { - vli_sub(a, a, b); - vli_rshift1(a); - if (vli_cmp(u, v) < 0) { - vli_add(u, u, p_mod); - } - vli_sub(u, u, v); - if (!vli_isEven(u)) { - l_carry = vli_add(u, u, p_mod); - } - vli_rshift1(u); - if (l_carry) { - u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; - } - } else { - vli_sub(b, b, a); - vli_rshift1(b); - if (vli_cmp(v, u) < 0) { - vli_add(v, v, p_mod); - } - vli_sub(v, v, u); - if (!vli_isEven(v)) { - l_carry = vli_add(v, v, p_mod); - } - vli_rshift1(v); - if (l_carry) { - v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; - } - } - } + while ((l_cmpResult = vli_cmp(a, b)) != 0) { + l_carry = 0; + if (vli_isEven(a)) { + vli_rshift1(a); + if (! vli_isEven(u)) { + l_carry = vli_add(u, u, p_mod); + } + vli_rshift1(u); + if (l_carry) { + u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; + } + } + else if (vli_isEven(b)) { + vli_rshift1(b); + if (! vli_isEven(v)) { + l_carry = vli_add(v, v, p_mod); + } + vli_rshift1(v); + if (l_carry) { + v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; + } + } + else if (l_cmpResult > 0) { + vli_sub(a, a, b); + vli_rshift1(a); + if (vli_cmp(u, v) < 0) { + vli_add(u, u, p_mod); + } + vli_sub(u, u, v); + if (! vli_isEven(u)) { + l_carry = vli_add(u, u, p_mod); + } + vli_rshift1(u); + if (l_carry) { + u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; + } + } + else { + vli_sub(b, b, a); + vli_rshift1(b); + if (vli_cmp(v, u) < 0) { + vli_add(v, v, p_mod); + } + vli_sub(v, v, u); + if (! vli_isEven(v)) { + l_carry = vli_add(v, v, p_mod); + } + vli_rshift1(v); + if (l_carry) { + v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; + } + } + } - vli_set(p_result, u); + vli_set(p_result, u); } -ZT_INLINE int EccPoint_isZero(EccPoint *p_point) -{ return (vli_isZero(p_point->x) && vli_isZero(p_point->y)); } - -void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t *Z1) +ZT_INLINE int EccPoint_isZero(EccPoint* p_point) { - /* t1 = X, t2 = Y, t3 = Z */ - uint64_t t4[NUM_ECC_DIGITS]; - uint64_t t5[NUM_ECC_DIGITS]; - - if (vli_isZero(Z1)) { - return; - } - - vli_modSquare_fast(t4, Y1); /* t4 = y1^2 */ - vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */ - vli_modSquare_fast(t4, t4); /* t4 = y1^4 */ - vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */ - vli_modSquare_fast(Z1, Z1); /* t3 = z1^2 */ - - vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */ - vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */ - vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */ - vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */ - - vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */ - vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */ - if (vli_testBit(X1, 0)) { - uint64_t l_carry = vli_add(X1, X1, curve_p); - vli_rshift1(X1); - X1[NUM_ECC_DIGITS - 1] |= l_carry << 63U; - } else { - vli_rshift1(X1); - } - /* t1 = 3/2*(x1^2 - z1^4) = B */ - - vli_modSquare_fast(Z1, X1); /* t3 = B^2 */ - vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */ - vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */ - vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */ - vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */ - vli_modSub(t4, X1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */ - - vli_set(X1, Z1); - vli_set(Z1, Y1); - vli_set(Y1, t4); + return (vli_isZero(p_point->x) && vli_isZero(p_point->y)); } -void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z) +void EccPoint_double_jacobian(uint64_t* X1, uint64_t* Y1, uint64_t* Z1) { - uint64_t t1[NUM_ECC_DIGITS]; + /* t1 = X, t2 = Y, t3 = Z */ + uint64_t t4[NUM_ECC_DIGITS]; + uint64_t t5[NUM_ECC_DIGITS]; - vli_modSquare_fast(t1, Z); /* z^2 */ - vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */ - vli_modMult_fast(t1, t1, Z); /* z^3 */ - vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */ + if (vli_isZero(Z1)) { + return; + } + + vli_modSquare_fast(t4, Y1); /* t4 = y1^2 */ + vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */ + vli_modSquare_fast(t4, t4); /* t4 = y1^4 */ + vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */ + vli_modSquare_fast(Z1, Z1); /* t3 = z1^2 */ + + vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */ + vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */ + vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */ + vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */ + + vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */ + vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */ + if (vli_testBit(X1, 0)) { + uint64_t l_carry = vli_add(X1, X1, curve_p); + vli_rshift1(X1); + X1[NUM_ECC_DIGITS - 1] |= l_carry << 63U; + } + else { + vli_rshift1(X1); + } + /* t1 = 3/2*(x1^2 - z1^4) = B */ + + vli_modSquare_fast(Z1, X1); /* t3 = B^2 */ + vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */ + vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */ + vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */ + vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */ + vli_modSub(t4, X1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */ + + vli_set(X1, Z1); + vli_set(Z1, Y1); + vli_set(Y1, t4); } -void XYcZ_initial_double(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2, uint64_t *p_initialZ) +void apply_z(uint64_t* X1, uint64_t* Y1, uint64_t* Z) { - uint64_t z[NUM_ECC_DIGITS]; + uint64_t t1[NUM_ECC_DIGITS]; - vli_set(X2, X1); - vli_set(Y2, Y1); - - vli_clear(z); - z[0] = 1; - if (p_initialZ) { - vli_set(z, p_initialZ); - } - - apply_z(X1, Y1, z); - - EccPoint_double_jacobian(X1, Y1, z); - - apply_z(X2, Y2, z); + vli_modSquare_fast(t1, Z); /* z^2 */ + vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */ + vli_modMult_fast(t1, t1, Z); /* z^3 */ + vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */ } -void XYcZ_add(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2) +void XYcZ_initial_double(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2, uint64_t* p_initialZ) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uint64_t t5[NUM_ECC_DIGITS]; + uint64_t z[NUM_ECC_DIGITS]; - vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ - vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ - vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ - vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ - vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ - vli_modSquare_fast(t5, Y2); /* t5 = (y2 - y1)^2 = D */ + vli_set(X2, X1); + vli_set(Y2, Y1); - vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */ - vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */ - vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */ - vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */ - vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */ - vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */ - vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ + vli_clear(z); + z[0] = 1; + if (p_initialZ) { + vli_set(z, p_initialZ); + } - vli_set(X2, t5); + apply_z(X1, Y1, z); + + EccPoint_double_jacobian(X1, Y1, z); + + apply_z(X2, Y2, z); } -void XYcZ_addC(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2) +void XYcZ_add(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uint64_t t5[NUM_ECC_DIGITS]; - uint64_t t6[NUM_ECC_DIGITS]; - uint64_t t7[NUM_ECC_DIGITS]; + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uint64_t t5[NUM_ECC_DIGITS]; - vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ - vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ - vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ - vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ - vli_modAdd(t5, Y2, Y1, curve_p); /* t4 = y2 + y1 */ - vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ + vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ + vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ + vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ + vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ + vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ + vli_modSquare_fast(t5, Y2); /* t5 = (y2 - y1)^2 = D */ - vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */ - vli_modMult_fast(Y1, Y1, t6); /* t2 = y1 * (C - B) */ - vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */ - vli_modSquare_fast(X2, Y2); /* t3 = (y2 - y1)^2 */ - vli_modSub(X2, X2, t6, curve_p); /* t3 = x3 */ + vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */ + vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */ + vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */ + vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */ + vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */ + vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */ + vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ - vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */ - vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */ - vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ - - vli_modSquare_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */ - vli_modSub(t7, t7, t6, curve_p); /* t7 = x3' */ - vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */ - vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */ - vli_modSub(Y1, t6, Y1, curve_p); /* t2 = y3' */ - - vli_set(X1, t7); + vli_set(X2, t5); } -void EccPoint_mult(EccPoint *p_result, const EccPoint *p_point, uint64_t *p_scalar, uint64_t *p_initialZ) +void XYcZ_addC(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2) { - /* R0 and R1 */ - uint64_t Rx[2][NUM_ECC_DIGITS]; - uint64_t Ry[2][NUM_ECC_DIGITS]; - uint64_t z[NUM_ECC_DIGITS]; + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uint64_t t5[NUM_ECC_DIGITS]; + uint64_t t6[NUM_ECC_DIGITS]; + uint64_t t7[NUM_ECC_DIGITS]; - int i, nb; + vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ + vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ + vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ + vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ + vli_modAdd(t5, Y2, Y1, curve_p); /* t4 = y2 + y1 */ + vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ - vli_set(Rx[1], p_point->x); - vli_set(Ry[1], p_point->y); + vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */ + vli_modMult_fast(Y1, Y1, t6); /* t2 = y1 * (C - B) */ + vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */ + vli_modSquare_fast(X2, Y2); /* t3 = (y2 - y1)^2 */ + vli_modSub(X2, X2, t6, curve_p); /* t3 = x3 */ - XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ); + vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */ + vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */ + vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ - for (i = (int)vli_numBits(p_scalar) - 2; i > 0; --i) { - nb = !vli_testBit(p_scalar, i); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]); - } + vli_modSquare_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */ + vli_modSub(t7, t7, t6, curve_p); /* t7 = x3' */ + vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */ + vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */ + vli_modSub(Y1, t6, Y1, curve_p); /* t2 = y3' */ - nb = !vli_testBit(p_scalar, 0); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); + vli_set(X1, t7); +} - /* Find final 1/Z value. */ - vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */ - vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */ - vli_modMult_fast(z, z, p_point->x); /* xP * Yb * (X1 - X0) */ - vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */ - vli_modMult_fast(z, z, p_point->y); /* yP / (xP * Yb * (X1 - X0)) */ - vli_modMult_fast(z, z, Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */ - /* End 1/Z calculation */ +void EccPoint_mult(EccPoint* p_result, const EccPoint* p_point, uint64_t* p_scalar, uint64_t* p_initialZ) +{ + /* R0 and R1 */ + uint64_t Rx[2][NUM_ECC_DIGITS]; + uint64_t Ry[2][NUM_ECC_DIGITS]; + uint64_t z[NUM_ECC_DIGITS]; - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]); + int i, nb; - apply_z(Rx[0], Ry[0], z); + vli_set(Rx[1], p_point->x); + vli_set(Ry[1], p_point->y); - vli_set(p_result->x, Rx[0]); - vli_set(p_result->y, Ry[0]); + XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ); + + for (i = (int)vli_numBits(p_scalar) - 2; i > 0; --i) { + nb = ! vli_testBit(p_scalar, i); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]); + } + + nb = ! vli_testBit(p_scalar, 0); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); + + /* Find final 1/Z value. */ + vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */ + vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */ + vli_modMult_fast(z, z, p_point->x); /* xP * Yb * (X1 - X0) */ + vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */ + vli_modMult_fast(z, z, p_point->y); /* yP / (xP * Yb * (X1 - X0)) */ + vli_modMult_fast(z, z, Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */ + /* End 1/Z calculation */ + + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]); + + apply_z(Rx[0], Ry[0], z); + + vli_set(p_result->x, Rx[0]); + vli_set(p_result->y, Ry[0]); } ZT_INLINE void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES]) { - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { - const uint8_t *p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); - p_native[i] = ((uint64_t)p_digit[0] << 56) | ((uint64_t)p_digit[1] << 48) | ((uint64_t)p_digit[2] << 40) | ((uint64_t)p_digit[3] << 32) | - ((uint64_t)p_digit[4] << 24) | ((uint64_t)p_digit[5] << 16) | ((uint64_t)p_digit[6] << 8) | (uint64_t)p_digit[7]; - } + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { + const uint8_t* p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); + p_native[i] = ((uint64_t)p_digit[0] << 56) | ((uint64_t)p_digit[1] << 48) | ((uint64_t)p_digit[2] << 40) + | ((uint64_t)p_digit[3] << 32) | ((uint64_t)p_digit[4] << 24) | ((uint64_t)p_digit[5] << 16) + | ((uint64_t)p_digit[6] << 8) | (uint64_t)p_digit[7]; + } } ZT_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS]) { - for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { - uint8_t *p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); - p_digit[0] = p_native[i] >> 56; - p_digit[1] = p_native[i] >> 48; - p_digit[2] = p_native[i] >> 40; - p_digit[3] = p_native[i] >> 32; - p_digit[4] = p_native[i] >> 24; - p_digit[5] = p_native[i] >> 16; - p_digit[6] = p_native[i] >> 8; - p_digit[7] = p_native[i]; - } + for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { + uint8_t* p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); + p_digit[0] = p_native[i] >> 56; + p_digit[1] = p_native[i] >> 48; + p_digit[2] = p_native[i] >> 40; + p_digit[3] = p_native[i] >> 32; + p_digit[4] = p_native[i] >> 24; + p_digit[5] = p_native[i] >> 16; + p_digit[6] = p_native[i] >> 8; + p_digit[7] = p_native[i]; + } } void mod_sqrt(uint64_t a[NUM_ECC_DIGITS]) { - uint64_t p1[NUM_ECC_DIGITS] = {1}; - uint64_t l_result[NUM_ECC_DIGITS] = {1}; + uint64_t p1[NUM_ECC_DIGITS] = { 1 }; + uint64_t l_result[NUM_ECC_DIGITS] = { 1 }; - vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */ - for (uint i = vli_numBits(p1) - 1; i > 1; --i) { - vli_modSquare_fast(l_result, l_result); - if (vli_testBit(p1, i)) { - vli_modMult_fast(l_result, l_result, a); - } - } - vli_set(a, l_result); + vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */ + for (uint i = vli_numBits(p1) - 1; i > 1; --i) { + vli_modSquare_fast(l_result, l_result); + if (vli_testBit(p1, i)) { + vli_modMult_fast(l_result, l_result, a); + } + } + vli_set(a, l_result); } -void ecc_point_decompress(EccPoint *p_point, const uint8_t p_compressed[ECC_BYTES + 1]) +void ecc_point_decompress(EccPoint* p_point, const uint8_t p_compressed[ECC_BYTES + 1]) { - uint64_t _3[NUM_ECC_DIGITS] = {3}; /* -a = 3 */ - ecc_bytes2native(p_point->x, p_compressed + 1); + uint64_t _3[NUM_ECC_DIGITS] = { 3 }; /* -a = 3 */ + ecc_bytes2native(p_point->x, p_compressed + 1); - vli_modSquare_fast(p_point->y, p_point->x); /* y = x^2 */ - vli_modSub(p_point->y, p_point->y, _3, curve_p); /* y = x^2 - 3 */ - vli_modMult_fast(p_point->y, p_point->y, p_point->x); /* y = x^3 - 3x */ - vli_modAdd(p_point->y, p_point->y, curve_b, curve_p); /* y = x^3 - 3x + b */ + vli_modSquare_fast(p_point->y, p_point->x); /* y = x^2 */ + vli_modSub(p_point->y, p_point->y, _3, curve_p); /* y = x^2 - 3 */ + vli_modMult_fast(p_point->y, p_point->y, p_point->x); /* y = x^3 - 3x */ + vli_modAdd(p_point->y, p_point->y, curve_b, curve_p); /* y = x^3 - 3x + b */ - mod_sqrt(p_point->y); + mod_sqrt(p_point->y); - if ((p_point->y[0] & 0x01) != (p_compressed[0] & 0x01)) { - vli_sub(p_point->y, curve_p, p_point->y); - } + if ((p_point->y[0] & 0x01) != (p_compressed[0] & 0x01)) { + vli_sub(p_point->y, curve_p, p_point->y); + } } ZT_INLINE int ecc_make_key(uint8_t p_publicKey[ECC_BYTES + 1], uint8_t p_privateKey[ECC_BYTES]) { - uint64_t l_private[NUM_ECC_DIGITS]; - EccPoint l_public; - unsigned l_tries = 0; + uint64_t l_private[NUM_ECC_DIGITS]; + EccPoint l_public; + unsigned l_tries = 0; - do { - if (!getRandomNumber(l_private) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { - return 0; - } - if (vli_isZero(l_private)) { - continue; - } + do { + if (! getRandomNumber(l_private) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { + return 0; + } + if (vli_isZero(l_private)) { + continue; + } - if (vli_cmp(curve_n, l_private) != 1) { - vli_sub(l_private, l_private, curve_n); - } + if (vli_cmp(curve_n, l_private) != 1) { + vli_sub(l_private, l_private, curve_n); + } - EccPoint_mult(&l_public, &curve_G, l_private, NULL); - } while (EccPoint_isZero(&l_public)); + EccPoint_mult(&l_public, &curve_G, l_private, NULL); + } while (EccPoint_isZero(&l_public)); - ecc_native2bytes(p_privateKey, l_private); - ecc_native2bytes(p_publicKey + 1, l_public.x); - p_publicKey[0] = 2 + (l_public.y[0] & 0x01); - return 1; + ecc_native2bytes(p_privateKey, l_private); + ecc_native2bytes(p_publicKey + 1, l_public.x); + p_publicKey[0] = 2 + (l_public.y[0] & 0x01); + return 1; } -ZT_INLINE int ecdh_shared_secret(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8_t p_privateKey[ECC_BYTES], uint8_t p_secret[ECC_BYTES]) +ZT_INLINE int ecdh_shared_secret( + const uint8_t p_publicKey[ECC_BYTES + 1], + const uint8_t p_privateKey[ECC_BYTES], + uint8_t p_secret[ECC_BYTES]) { - EccPoint l_public; - uint64_t l_private[NUM_ECC_DIGITS]; - uint64_t l_random[NUM_ECC_DIGITS]; + EccPoint l_public; + uint64_t l_private[NUM_ECC_DIGITS]; + uint64_t l_random[NUM_ECC_DIGITS]; - if (!getRandomNumber(l_random)) { - return 0; - } + if (! getRandomNumber(l_random)) { + return 0; + } - ecc_point_decompress(&l_public, p_publicKey); - ecc_bytes2native(l_private, p_privateKey); + ecc_point_decompress(&l_public, p_publicKey); + ecc_bytes2native(l_private, p_privateKey); - EccPoint l_product; - EccPoint_mult(&l_product, &l_public, l_private, l_random); + EccPoint l_product; + EccPoint_mult(&l_product, &l_public, l_private, l_random); - ecc_native2bytes(p_secret, l_product.x); + ecc_native2bytes(p_secret, l_product.x); - return !EccPoint_isZero(&l_product); + return ! EccPoint_isZero(&l_product); } /* Computes p_result = (p_left * p_right) % p_mod. */ -void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, const uint64_t *p_mod) +void vli_modMult(uint64_t* p_result, uint64_t* p_left, uint64_t* p_right, const uint64_t* p_mod) { - uint64_t l_product[2 * NUM_ECC_DIGITS]; - uint64_t l_modMultiple[2 * NUM_ECC_DIGITS]; - uint l_digitShift, l_bitShift; - uint l_productBits; - uint l_modBits = vli_numBits(p_mod); + uint64_t l_product[2 * NUM_ECC_DIGITS]; + uint64_t l_modMultiple[2 * NUM_ECC_DIGITS]; + uint l_digitShift, l_bitShift; + uint l_productBits; + uint l_modBits = vli_numBits(p_mod); - vli_mult(l_product, p_left, p_right); - l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS); - if (l_productBits) { - l_productBits += NUM_ECC_DIGITS * 64; - } else { - l_productBits = vli_numBits(l_product); - } + vli_mult(l_product, p_left, p_right); + l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS); + if (l_productBits) { + l_productBits += NUM_ECC_DIGITS * 64; + } + else { + l_productBits = vli_numBits(l_product); + } - if (l_productBits < l_modBits) { /* l_product < p_mod. */ - vli_set(p_result, l_product); - return; - } + if (l_productBits < l_modBits) { /* l_product < p_mod. */ + vli_set(p_result, l_product); + return; + } - /* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest - power of two possible while still resulting in a number less than p_left. */ - vli_clear(l_modMultiple); - vli_clear(l_modMultiple + NUM_ECC_DIGITS); - l_digitShift = (l_productBits - l_modBits) / 64; - l_bitShift = (l_productBits - l_modBits) % 64; - if (l_bitShift) { - l_modMultiple[l_digitShift + NUM_ECC_DIGITS] = vli_lshift(l_modMultiple + l_digitShift, p_mod, l_bitShift); - } else { - vli_set(l_modMultiple + l_digitShift, p_mod); - } + /* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest + power of two possible while still resulting in a number less than p_left. */ + vli_clear(l_modMultiple); + vli_clear(l_modMultiple + NUM_ECC_DIGITS); + l_digitShift = (l_productBits - l_modBits) / 64; + l_bitShift = (l_productBits - l_modBits) % 64; + if (l_bitShift) { + l_modMultiple[l_digitShift + NUM_ECC_DIGITS] = vli_lshift(l_modMultiple + l_digitShift, p_mod, l_bitShift); + } + else { + vli_set(l_modMultiple + l_digitShift, p_mod); + } - /* Subtract all multiples of p_mod to get the remainder. */ - vli_clear(p_result); - p_result[0] = 1; /* Use p_result as a temp var to store 1 (for subtraction) */ - while (l_productBits > NUM_ECC_DIGITS * 64 || vli_cmp(l_modMultiple, p_mod) >= 0) { - int l_cmp = vli_cmp(l_modMultiple + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS); - if (l_cmp < 0 || (l_cmp == 0 && vli_cmp(l_modMultiple, l_product) <= 0)) { - if (vli_sub(l_product, l_product, l_modMultiple)) { /* borrow */ - vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, p_result); - } - vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, l_modMultiple + NUM_ECC_DIGITS); - } - uint64_t l_carry = (l_modMultiple[NUM_ECC_DIGITS] & 0x01) << 63; - vli_rshift1(l_modMultiple + NUM_ECC_DIGITS); - vli_rshift1(l_modMultiple); - l_modMultiple[NUM_ECC_DIGITS - 1] |= l_carry; + /* Subtract all multiples of p_mod to get the remainder. */ + vli_clear(p_result); + p_result[0] = 1; /* Use p_result as a temp var to store 1 (for subtraction) */ + while (l_productBits > NUM_ECC_DIGITS * 64 || vli_cmp(l_modMultiple, p_mod) >= 0) { + int l_cmp = vli_cmp(l_modMultiple + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS); + if (l_cmp < 0 || (l_cmp == 0 && vli_cmp(l_modMultiple, l_product) <= 0)) { + if (vli_sub(l_product, l_product, l_modMultiple)) { /* borrow */ + vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, p_result); + } + vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, l_modMultiple + NUM_ECC_DIGITS); + } + uint64_t l_carry = (l_modMultiple[NUM_ECC_DIGITS] & 0x01) << 63; + vli_rshift1(l_modMultiple + NUM_ECC_DIGITS); + vli_rshift1(l_modMultiple); + l_modMultiple[NUM_ECC_DIGITS - 1] |= l_carry; - --l_productBits; - } - vli_set(p_result, l_product); + --l_productBits; + } + vli_set(p_result, l_product); } ZT_INLINE uint umax(uint a, uint b) { - return (a > b ? a : b); + return (a > b ? a : b); } -ZT_INLINE int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_hash[ECC_BYTES], uint8_t p_signature[ECC_BYTES * 2]) +ZT_INLINE int +ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_hash[ECC_BYTES], uint8_t p_signature[ECC_BYTES * 2]) { - uint64_t k[NUM_ECC_DIGITS]; - uint64_t l_tmp[NUM_ECC_DIGITS]; - uint64_t l_s[NUM_ECC_DIGITS]; - EccPoint p; - unsigned l_tries = 0; + uint64_t k[NUM_ECC_DIGITS]; + uint64_t l_tmp[NUM_ECC_DIGITS]; + uint64_t l_s[NUM_ECC_DIGITS]; + EccPoint p; + unsigned l_tries = 0; - do { - if (!getRandomNumber(k) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { - return 0; - } - if (vli_isZero(k)) { - continue; - } + do { + if (! getRandomNumber(k) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { + return 0; + } + if (vli_isZero(k)) { + continue; + } - if (vli_cmp(curve_n, k) != 1) { - vli_sub(k, k, curve_n); - } + if (vli_cmp(curve_n, k) != 1) { + vli_sub(k, k, curve_n); + } - /* tmp = k * G */ - EccPoint_mult(&p, &curve_G, k, NULL); + /* tmp = k * G */ + EccPoint_mult(&p, &curve_G, k, NULL); - /* r = x1 (mod n) */ - if (vli_cmp(curve_n, p.x) != 1) { - vli_sub(p.x, p.x, curve_n); - } - } while (vli_isZero(p.x)); + /* r = x1 (mod n) */ + if (vli_cmp(curve_n, p.x) != 1) { + vli_sub(p.x, p.x, curve_n); + } + } while (vli_isZero(p.x)); - ecc_native2bytes(p_signature, p.x); + ecc_native2bytes(p_signature, p.x); - ecc_bytes2native(l_tmp, p_privateKey); - vli_modMult(l_s, p.x, l_tmp, curve_n); /* s = r*d */ - ecc_bytes2native(l_tmp, p_hash); - vli_modAdd(l_s, l_tmp, l_s, curve_n); /* s = e + r*d */ - vli_modInv(k, k, curve_n); /* k = 1 / k */ - vli_modMult(l_s, l_s, k, curve_n); /* s = (e + r*d) / k */ - ecc_native2bytes(p_signature + ECC_BYTES, l_s); + ecc_bytes2native(l_tmp, p_privateKey); + vli_modMult(l_s, p.x, l_tmp, curve_n); /* s = r*d */ + ecc_bytes2native(l_tmp, p_hash); + vli_modAdd(l_s, l_tmp, l_s, curve_n); /* s = e + r*d */ + vli_modInv(k, k, curve_n); /* k = 1 / k */ + vli_modMult(l_s, l_s, k, curve_n); /* s = (e + r*d) / k */ + ecc_native2bytes(p_signature + ECC_BYTES, l_s); - return 1; + return 1; } -ZT_INLINE int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8_t p_hash[ECC_BYTES], const uint8_t p_signature[ECC_BYTES * 2]) +ZT_INLINE int ecdsa_verify( + const uint8_t p_publicKey[ECC_BYTES + 1], + const uint8_t p_hash[ECC_BYTES], + const uint8_t p_signature[ECC_BYTES * 2]) { - uint64_t u1[NUM_ECC_DIGITS], u2[NUM_ECC_DIGITS]; - uint64_t z[NUM_ECC_DIGITS]; - EccPoint l_public, l_sum; - uint64_t rx[NUM_ECC_DIGITS]; - uint64_t ry[NUM_ECC_DIGITS]; - uint64_t tx[NUM_ECC_DIGITS]; - uint64_t ty[NUM_ECC_DIGITS]; - uint64_t tz[NUM_ECC_DIGITS]; + uint64_t u1[NUM_ECC_DIGITS], u2[NUM_ECC_DIGITS]; + uint64_t z[NUM_ECC_DIGITS]; + EccPoint l_public, l_sum; + uint64_t rx[NUM_ECC_DIGITS]; + uint64_t ry[NUM_ECC_DIGITS]; + uint64_t tx[NUM_ECC_DIGITS]; + uint64_t ty[NUM_ECC_DIGITS]; + uint64_t tz[NUM_ECC_DIGITS]; - uint64_t l_r[NUM_ECC_DIGITS], l_s[NUM_ECC_DIGITS]; + uint64_t l_r[NUM_ECC_DIGITS], l_s[NUM_ECC_DIGITS]; - ecc_point_decompress(&l_public, p_publicKey); - ecc_bytes2native(l_r, p_signature); - ecc_bytes2native(l_s, p_signature + ECC_BYTES); + ecc_point_decompress(&l_public, p_publicKey); + ecc_bytes2native(l_r, p_signature); + ecc_bytes2native(l_s, p_signature + ECC_BYTES); - if (vli_isZero(l_r) || vli_isZero(l_s)) { /* r, s must not be 0. */ - return 0; - } + if (vli_isZero(l_r) || vli_isZero(l_s)) { /* r, s must not be 0. */ + return 0; + } - if (vli_cmp(curve_n, l_r) != 1 || vli_cmp(curve_n, l_s) != 1) { /* r, s must be < n. */ - return 0; - } + if (vli_cmp(curve_n, l_r) != 1 || vli_cmp(curve_n, l_s) != 1) { /* r, s must be < n. */ + return 0; + } - /* Calculate u1 and u2. */ - vli_modInv(z, l_s, curve_n); /* Z = s^-1 */ - ecc_bytes2native(u1, p_hash); - vli_modMult(u1, u1, z, curve_n); /* u1 = e/s */ - vli_modMult(u2, l_r, z, curve_n); /* u2 = r/s */ + /* Calculate u1 and u2. */ + vli_modInv(z, l_s, curve_n); /* Z = s^-1 */ + ecc_bytes2native(u1, p_hash); + vli_modMult(u1, u1, z, curve_n); /* u1 = e/s */ + vli_modMult(u2, l_r, z, curve_n); /* u2 = r/s */ - /* Calculate l_sum = G + Q. */ - vli_set(l_sum.x, l_public.x); - vli_set(l_sum.y, l_public.y); - vli_set(tx, curve_G.x); - vli_set(ty, curve_G.y); - vli_modSub(z, l_sum.x, tx, curve_p); /* Z = x2 - x1 */ - XYcZ_add(tx, ty, l_sum.x, l_sum.y); - vli_modInv(z, z, curve_p); /* Z = 1/Z */ - apply_z(l_sum.x, l_sum.y, z); + /* Calculate l_sum = G + Q. */ + vli_set(l_sum.x, l_public.x); + vli_set(l_sum.y, l_public.y); + vli_set(tx, curve_G.x); + vli_set(ty, curve_G.y); + vli_modSub(z, l_sum.x, tx, curve_p); /* Z = x2 - x1 */ + XYcZ_add(tx, ty, l_sum.x, l_sum.y); + vli_modInv(z, z, curve_p); /* Z = 1/Z */ + apply_z(l_sum.x, l_sum.y, z); - /* Use Shamir's trick to calculate u1*G + u2*Q */ - const EccPoint *l_points[4] = {NULL, &curve_G, &l_public, &l_sum}; - uint l_numBits = umax(vli_numBits(u1), vli_numBits(u2)); + /* Use Shamir's trick to calculate u1*G + u2*Q */ + const EccPoint* l_points[4] = { NULL, &curve_G, &l_public, &l_sum }; + uint l_numBits = umax(vli_numBits(u1), vli_numBits(u2)); - const EccPoint *l_point = l_points[(!!vli_testBit(u1, l_numBits - 1)) | ((!!vli_testBit(u2, l_numBits - 1)) << 1)]; - vli_set(rx, l_point->x); - vli_set(ry, l_point->y); - vli_clear(z); - z[0] = 1; + const EccPoint* l_point = + l_points[(! ! vli_testBit(u1, l_numBits - 1)) | ((! ! vli_testBit(u2, l_numBits - 1)) << 1)]; + vli_set(rx, l_point->x); + vli_set(ry, l_point->y); + vli_clear(z); + z[0] = 1; - int i; - for (i = l_numBits - 2; i >= 0; --i) { - EccPoint_double_jacobian(rx, ry, z); + int i; + for (i = l_numBits - 2; i >= 0; --i) { + EccPoint_double_jacobian(rx, ry, z); - int l_index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1); - const EccPoint *l_point = l_points[l_index]; - if (l_point) { - vli_set(tx, l_point->x); - vli_set(ty, l_point->y); - apply_z(tx, ty, z); - vli_modSub(tz, rx, tx, curve_p); /* Z = x2 - x1 */ - XYcZ_add(tx, ty, rx, ry); - vli_modMult_fast(z, z, tz); - } - } + int l_index = (! ! vli_testBit(u1, i)) | ((! ! vli_testBit(u2, i)) << 1); + const EccPoint* l_point = l_points[l_index]; + if (l_point) { + vli_set(tx, l_point->x); + vli_set(ty, l_point->y); + apply_z(tx, ty, z); + vli_modSub(tz, rx, tx, curve_p); /* Z = x2 - x1 */ + XYcZ_add(tx, ty, rx, ry); + vli_modMult_fast(z, z, tz); + } + } - vli_modInv(z, z, curve_p); /* Z = 1/Z */ - apply_z(rx, ry, z); + vli_modInv(z, z, curve_p); /* Z = 1/Z */ + apply_z(rx, ry, z); - /* v = x1 (mod n) */ - if (vli_cmp(curve_n, rx) != 1) { - vli_sub(rx, rx, curve_n); - } + /* v = x1 (mod n) */ + if (vli_cmp(curve_n, rx) != 1) { + vli_sub(rx, rx, curve_n); + } - /* Accept only if v == r. */ - return (vli_cmp(rx, l_r) == 0); + /* Accept only if v == r. */ + return (vli_cmp(rx, l_r) == 0); } -} // anonymous namespace +} // anonymous namespace void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]) { - if (!ecc_make_key(pub, priv)) { - fprintf(stderr, "FATAL: ecdsa_make_key() failed!" ZT_EOL_S); - abort(); - } + if (! ecc_make_key(pub, priv)) { + fprintf(stderr, "FATAL: ecdsa_make_key() failed!" ZT_EOL_S); + abort(); + } } -void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE], const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) +void ECC384ECDSASign( + const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE], + const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], + uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) { - if (!ecdsa_sign(priv, hash, sig)) { - fprintf(stderr, "FATAL: ecdsa_sign() failed!" ZT_EOL_S); - abort(); - } + if (! ecdsa_sign(priv, hash, sig)) { + fprintf(stderr, "FATAL: ecdsa_sign() failed!" ZT_EOL_S); + abort(); + } } -bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) +bool ECC384ECDSAVerify( + const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], + const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], + const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) { - return (ecdsa_verify(pub, hash, sig) != 0); + return (ecdsa_verify(pub, hash, sig) != 0); } -bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE], const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE], uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]) +bool ECC384ECDH( + const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE], + const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE], + uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]) { - return (ecdh_shared_secret(theirPub, ourPriv, secret) != 0); + return (ecdh_shared_secret(theirPub, ourPriv, secret) != 0); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/ECC384.hpp b/core/ECC384.hpp index 1aa13bce4..c292b647f 100644 --- a/core/ECC384.hpp +++ b/core/ECC384.hpp @@ -65,7 +65,7 @@ namespace ZeroTier { * @param pub Buffer to receive point compressed public key * @param priv Buffer to receiver private key */ -void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]); +void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]); /** * Sign a hash with a NIST P-384 private key @@ -77,7 +77,10 @@ void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_EC * @param hash 48-byte hash * @param sig Buffer to receive signature */ -void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); +void ECC384ECDSASign( + const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE], + const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], + uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); /** * Verify a signature @@ -87,7 +90,10 @@ void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_ * @param sig Signature to check * @return True if signature is valid */ -bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); +bool ECC384ECDSAVerify( + const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], + const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], + const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); /** * Perform ECDH key agreement @@ -99,8 +105,11 @@ bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_ * @param ourPriv Local private key * @param secret Buffer to receive 48-byte secret */ -bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]); +bool ECC384ECDH( + const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE], + const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE], + uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Endpoint.cpp b/core/Endpoint.cpp index d501d9a64..249b343fe 100644 --- a/core/Endpoint.cpp +++ b/core/Endpoint.cpp @@ -12,257 +12,278 @@ /****/ #include "Endpoint.hpp" + #include "Utils.hpp" namespace ZeroTier { static ZT_INLINE char s_endpointTypeChar(const ZT_EndpointType t) { - switch(t) { - default: return '0'; - case ZT_ENDPOINT_TYPE_ZEROTIER: return 'z'; - case ZT_ENDPOINT_TYPE_ETHERNET: return 'e'; - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: return 'd'; - case ZT_ENDPOINT_TYPE_BLUETOOTH: return 'b'; - case ZT_ENDPOINT_TYPE_IP: return 'i'; - case ZT_ENDPOINT_TYPE_IP_UDP: return 'u'; - case ZT_ENDPOINT_TYPE_IP_TCP: return 't'; - case ZT_ENDPOINT_TYPE_IP_TCP_WS: return 'w'; - } + switch (t) { + default: + return '0'; + case ZT_ENDPOINT_TYPE_ZEROTIER: + return 'z'; + case ZT_ENDPOINT_TYPE_ETHERNET: + return 'e'; + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + return 'd'; + case ZT_ENDPOINT_TYPE_BLUETOOTH: + return 'b'; + case ZT_ENDPOINT_TYPE_IP: + return 'i'; + case ZT_ENDPOINT_TYPE_IP_UDP: + return 'u'; + case ZT_ENDPOINT_TYPE_IP_TCP: + return 't'; + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return 'w'; + } } static ZT_INLINE ZT_EndpointType s_charEndpointType(const char c) { - switch(c) { - default: return ZT_ENDPOINT_TYPE_NIL; - case 'z': return ZT_ENDPOINT_TYPE_ZEROTIER; - case 'e': return ZT_ENDPOINT_TYPE_ETHERNET; - case 'd': return ZT_ENDPOINT_TYPE_WIFI_DIRECT; - case 'b': return ZT_ENDPOINT_TYPE_BLUETOOTH; - case 'i': return ZT_ENDPOINT_TYPE_IP; - case 'u': return ZT_ENDPOINT_TYPE_IP_UDP; - case 't': return ZT_ENDPOINT_TYPE_IP_TCP; - case 'w': return ZT_ENDPOINT_TYPE_IP_TCP_WS; - } + switch (c) { + default: + return ZT_ENDPOINT_TYPE_NIL; + case 'z': + return ZT_ENDPOINT_TYPE_ZEROTIER; + case 'e': + return ZT_ENDPOINT_TYPE_ETHERNET; + case 'd': + return ZT_ENDPOINT_TYPE_WIFI_DIRECT; + case 'b': + return ZT_ENDPOINT_TYPE_BLUETOOTH; + case 'i': + return ZT_ENDPOINT_TYPE_IP; + case 'u': + return ZT_ENDPOINT_TYPE_IP_UDP; + case 't': + return ZT_ENDPOINT_TYPE_IP_TCP; + case 'w': + return ZT_ENDPOINT_TYPE_IP_TCP_WS; + } } -char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept +char* Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept { - static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow"); - static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow"); + static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow"); + static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow"); - s[0] = s_endpointTypeChar(this->type); - switch (this->type) { - default: // ZT_ENDPOINT_TYPE_NIL - s[1] = 0; - break; - case ZT_ENDPOINT_TYPE_ZEROTIER: - s[1] = '/'; - zt().toString(s + 2); - break; - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - s[1] = '/'; - eth().toString(s + 2); - break; - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - s[1] = '/'; - ip().toString(s + 2); - break; - } + s[0] = s_endpointTypeChar(this->type); + switch (this->type) { + default: // ZT_ENDPOINT_TYPE_NIL + s[1] = 0; + break; + case ZT_ENDPOINT_TYPE_ZEROTIER: + s[1] = '/'; + zt().toString(s + 2); + break; + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + s[1] = '/'; + eth().toString(s + 2); + break; + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + s[1] = '/'; + ip().toString(s + 2); + break; + } - return s; + return s; } -bool Endpoint::fromString(const char *s) noexcept +bool Endpoint::fromString(const char* s) noexcept { - memoryZero(this); - if ((!s) || (!*s)) { - // Empty strings are considered NIL endpoints. - return true; - } else if (s[1] == '/') { - // type/ADDRESS is a fully qualified endpoint. - this->type = s_charEndpointType(s[0]); - switch(this->type) { - case ZT_ENDPOINT_TYPE_NIL: - break; - case ZT_ENDPOINT_TYPE_ZEROTIER: - if (!s[2]) - return false; - break; - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: { - if (!s[2]) - return false; - MAC tmpmac; - tmpmac.fromString(s + 2); - this->value.mac = tmpmac.toInt(); - } break; - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: { - if (!s[2]) - return false; - if (!asInetAddress(this->value.ss).fromString(s + 2)) - return false; - } break; - } - } else if (strchr(s, '/') != nullptr) { - // IP/port is parsed as an IP_UDP endpoint for backward compatibility. - this->type = ZT_ENDPOINT_TYPE_IP_UDP; - return asInetAddress(this->value.ss).fromString(s); - } - return false; + memoryZero(this); + if ((! s) || (! *s)) { + // Empty strings are considered NIL endpoints. + return true; + } + else if (s[1] == '/') { + // type/ADDRESS is a fully qualified endpoint. + this->type = s_charEndpointType(s[0]); + switch (this->type) { + case ZT_ENDPOINT_TYPE_NIL: + break; + case ZT_ENDPOINT_TYPE_ZEROTIER: + if (! s[2]) + return false; + break; + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: { + if (! s[2]) + return false; + MAC tmpmac; + tmpmac.fromString(s + 2); + this->value.mac = tmpmac.toInt(); + } break; + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: { + if (! s[2]) + return false; + if (! asInetAddress(this->value.ss).fromString(s + 2)) + return false; + } break; + } + } + else if (strchr(s, '/') != nullptr) { + // IP/port is parsed as an IP_UDP endpoint for backward compatibility. + this->type = ZT_ENDPOINT_TYPE_IP_UDP; + return asInetAddress(this->value.ss).fromString(s); + } + return false; } int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept { - switch (this->type) { - default: // ZT_ENDPOINT_TYPE_NIL - // NIL endpoints get serialized like NIL InetAddress instances. - data[0] = ZT_ENDPOINT_TYPE_NIL; - return 1; + switch (this->type) { + default: // ZT_ENDPOINT_TYPE_NIL + // NIL endpoints get serialized like NIL InetAddress instances. + data[0] = ZT_ENDPOINT_TYPE_NIL; + return 1; - case ZT_ENDPOINT_TYPE_ZEROTIER: - data[0] = 16 + ZT_ENDPOINT_TYPE_ZEROTIER; - Address(this->value.fp.address).copyTo(data + 1); - Utils::copy(data + 1 + ZT_ADDRESS_LENGTH, this->value.fp.hash); - return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE; + case ZT_ENDPOINT_TYPE_ZEROTIER: + data[0] = 16 + ZT_ENDPOINT_TYPE_ZEROTIER; + Address(this->value.fp.address).copyTo(data + 1); + Utils::copy(data + 1 + ZT_ADDRESS_LENGTH, this->value.fp.hash); + return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE; - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - data[0] = 16 + (uint8_t)this->type; - MAC(this->value.mac).copyTo(data + 1); - return 7; + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + data[0] = 16 + (uint8_t)this->type; + MAC(this->value.mac).copyTo(data + 1); + return 7; - case ZT_ENDPOINT_TYPE_IP_UDP: - // Default UDP mode gets serialized to look exactly like an InetAddress. - return asInetAddress(this->value.ss).marshal(data); + case ZT_ENDPOINT_TYPE_IP_UDP: + // Default UDP mode gets serialized to look exactly like an InetAddress. + return asInetAddress(this->value.ss).marshal(data); - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - // Other IP types get serialized as new version Endpoint instances with type. - data[0] = 16 + (uint8_t)this->type; - return 1 + asInetAddress(this->value.ss).marshal(data + 1); - } + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + // Other IP types get serialized as new version Endpoint instances with type. + data[0] = 16 + (uint8_t)this->type; + return 1 + asInetAddress(this->value.ss).marshal(data + 1); + } } -int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept +int Endpoint::unmarshal(const uint8_t* restrict data, int len) noexcept { - memoryZero(this); - if (unlikely(len <= 0)) - return -1; + memoryZero(this); + if (unlikely(len <= 0)) + return -1; - // Serialized endpoints with type bytes less than 16 are passed through - // to the unmarshal method of InetAddress and considered UDP endpoints. - // This allows backward compatibility with old endpoint fields in the - // protocol that were serialized InetAddress instances. + // Serialized endpoints with type bytes less than 16 are passed through + // to the unmarshal method of InetAddress and considered UDP endpoints. + // This allows backward compatibility with old endpoint fields in the + // protocol that were serialized InetAddress instances. - if (data[0] < 16) { - switch (data[0]) { - case 0: - return 1; - case 4: - case 6: - this->type = ZT_ENDPOINT_TYPE_IP_UDP; - return asInetAddress(this->value.ss).unmarshal(data, len); - } - return -1; - } + if (data[0] < 16) { + switch (data[0]) { + case 0: + return 1; + case 4: + case 6: + this->type = ZT_ENDPOINT_TYPE_IP_UDP; + return asInetAddress(this->value.ss).unmarshal(data, len); + } + return -1; + } - switch ((this->type = (ZT_EndpointType)(data[0] - 16))) { - case ZT_ENDPOINT_TYPE_NIL: - return 1; + switch ((this->type = (ZT_EndpointType)(data[0] - 16))) { + case ZT_ENDPOINT_TYPE_NIL: + return 1; - case ZT_ENDPOINT_TYPE_ZEROTIER: - if (len >= (1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE)) { - this->value.fp.address = Address(data + 1).toInt(); - Utils::copy(this->value.fp.hash, data + 1 + ZT_ADDRESS_LENGTH); - return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE; - } - return -1; + case ZT_ENDPOINT_TYPE_ZEROTIER: + if (len >= (1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE)) { + this->value.fp.address = Address(data + 1).toInt(); + Utils::copy(this->value.fp.hash, data + 1 + ZT_ADDRESS_LENGTH); + return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE; + } + return -1; - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - if (len >= 7) { - MAC tmp; - tmp.setTo(data + 1); - this->value.mac = tmp.toInt(); - return 7; - } - return -1; + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + if (len >= 7) { + MAC tmp; + tmp.setTo(data + 1); + this->value.mac = tmp.toInt(); + return 7; + } + return -1; - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1); + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1); - default: - break; - } + default: + break; + } - // Unrecognized types can still be passed over in a valid stream if they are - // prefixed by a 16-bit size. This allows forward compatibility with future - // endpoint types. - this->type = ZT_ENDPOINT_TYPE_NIL; - if (len < 3) - return -1; - const int unrecLen = 1 + (int) Utils::loadBigEndian(data + 1); - return (unrecLen > len) ? -1 : unrecLen; + // Unrecognized types can still be passed over in a valid stream if they are + // prefixed by a 16-bit size. This allows forward compatibility with future + // endpoint types. + this->type = ZT_ENDPOINT_TYPE_NIL; + if (len < 3) + return -1; + const int unrecLen = 1 + (int)Utils::loadBigEndian(data + 1); + return (unrecLen > len) ? -1 : unrecLen; } -bool Endpoint::operator==(const Endpoint &ep) const noexcept +bool Endpoint::operator==(const Endpoint& ep) const noexcept { - if (this->type == ep.type) { - switch(this->type) { - case ZT_ENDPOINT_TYPE_ZEROTIER: - return zt() == ep.zt(); - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - return this->value.mac == ep.value.mac; - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return ip() == ep.ip(); - default: - return true; - } - } - return false; + if (this->type == ep.type) { + switch (this->type) { + case ZT_ENDPOINT_TYPE_ZEROTIER: + return zt() == ep.zt(); + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + return this->value.mac == ep.value.mac; + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return ip() == ep.ip(); + default: + return true; + } + } + return false; } -bool Endpoint::operator<(const Endpoint &ep) const noexcept +bool Endpoint::operator<(const Endpoint& ep) const noexcept { - if (this->type == ep.type) { - switch(this->type) { - case ZT_ENDPOINT_TYPE_ZEROTIER: - return zt() < ep.zt(); - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - return this->value.mac < ep.value.mac; - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return ip() < ep.ip(); - default: - return true; - } - } - return (int)this->type < (int)ep.type; + if (this->type == ep.type) { + switch (this->type) { + case ZT_ENDPOINT_TYPE_ZEROTIER: + return zt() < ep.zt(); + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + return this->value.mac < ep.value.mac; + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return ip() < ep.ip(); + default: + return true; + } + } + return (int)this->type < (int)ep.type; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Endpoint.hpp b/core/Endpoint.hpp index 200c7f2b0..f8dadd879 100644 --- a/core/Endpoint.hpp +++ b/core/Endpoint.hpp @@ -14,226 +14,260 @@ #ifndef ZT_ENDPOINT_HPP #define ZT_ENDPOINT_HPP -#include "Constants.hpp" -#include "InetAddress.hpp" #include "Address.hpp" -#include "Utils.hpp" -#include "TriviallyCopyable.hpp" +#include "Constants.hpp" #include "Fingerprint.hpp" +#include "InetAddress.hpp" #include "MAC.hpp" +#include "TriviallyCopyable.hpp" +#include "Utils.hpp" -#define ZT_ENDPOINT_STRING_SIZE_MAX 256 +#define ZT_ENDPOINT_STRING_SIZE_MAX 256 #define ZT_ENDPOINT_MARSHAL_SIZE_MAX 192 namespace ZeroTier { -static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > ZT_INETADDRESS_MARSHAL_SIZE_MAX, "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); -static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(ZT_Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); -static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(InetAddress), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); +static_assert( + (ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > ZT_INETADDRESS_MARSHAL_SIZE_MAX, + "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); +static_assert( + (ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(ZT_Fingerprint), + "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); +static_assert( + (ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(InetAddress), + "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(MAC), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); -static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); +static_assert( + (ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint), + "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); /** * Endpoint variant specifying some form of network endpoint. - * + * * This is sort of a superset of InetAddress and for the standard UDP * protocol marshals and unmarshals to a compatible format. This makes * it backward compatible with older node versions' protocol fields * where InetAddress was used as long as only the UDP type is exchanged * with those nodes. */ -class Endpoint : public ZT_Endpoint, public TriviallyCopyable -{ -public: - /** - * Create a NIL/empty endpoint - */ - ZT_INLINE Endpoint() noexcept - { memoryZero(this); } +class Endpoint + : public ZT_Endpoint + , public TriviallyCopyable { + public: + /** + * Create a NIL/empty endpoint + */ + ZT_INLINE Endpoint() noexcept + { + memoryZero(this); + } - ZT_INLINE Endpoint(const ZT_Endpoint &ep) noexcept - { Utils::copy< sizeof(ZT_Endpoint) >((ZT_Endpoint *)this, &ep); } + ZT_INLINE Endpoint(const ZT_Endpoint& ep) noexcept + { + Utils::copy((ZT_Endpoint*)this, &ep); + } - /** - * Create an endpoint for a type that uses an IP - * - * @param a IP/port - * @param et Endpoint type (default: IP_UDP) - */ - ZT_INLINE Endpoint(const InetAddress &inaddr, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept - { - if (inaddr) { - this->type = et; - Utils::copy< sizeof(struct sockaddr_storage) >(&(this->value.ss), &(inaddr.as.ss)); - } else { - memoryZero(this); - } - } + /** + * Create an endpoint for a type that uses an IP + * + * @param a IP/port + * @param et Endpoint type (default: IP_UDP) + */ + ZT_INLINE Endpoint(const InetAddress& inaddr, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept + { + if (inaddr) { + this->type = et; + Utils::copy(&(this->value.ss), &(inaddr.as.ss)); + } + else { + memoryZero(this); + } + } - /** - * Create an endpoint for ZeroTier relaying (ZEROTIER type) - * - * @param zt_ ZeroTier identity fingerprint - */ - ZT_INLINE Endpoint(const Fingerprint &zt_) noexcept - { - if (zt_) { - this->type = ZT_ENDPOINT_TYPE_ZEROTIER; - this->value.fp = zt_; - } else { - memoryZero(this); - } - } + /** + * Create an endpoint for ZeroTier relaying (ZEROTIER type) + * + * @param zt_ ZeroTier identity fingerprint + */ + ZT_INLINE Endpoint(const Fingerprint& zt_) noexcept + { + if (zt_) { + this->type = ZT_ENDPOINT_TYPE_ZEROTIER; + this->value.fp = zt_; + } + else { + memoryZero(this); + } + } - /** - * Create an endpoint for a type that uses a MAC address - * - * @param eth_ Ethernet address - * @param et Endpoint type (default: ETHERNET) - */ - ZT_INLINE Endpoint(const MAC ð_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept - { - if (eth_) { - this->type = et; - this->value.mac = eth_.toInt(); - } else { - memoryZero(this); - } - } + /** + * Create an endpoint for a type that uses a MAC address + * + * @param eth_ Ethernet address + * @param et Endpoint type (default: ETHERNET) + */ + ZT_INLINE Endpoint(const MAC& eth_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept + { + if (eth_) { + this->type = et; + this->value.mac = eth_.toInt(); + } + else { + memoryZero(this); + } + } - /** - * @return True if endpoint type isn't NIL - */ - ZT_INLINE operator bool() const noexcept - { return this->type != ZT_ENDPOINT_TYPE_NIL; } + /** + * @return True if endpoint type isn't NIL + */ + ZT_INLINE operator bool() const noexcept + { + return this->type != ZT_ENDPOINT_TYPE_NIL; + } - /** - * @return True if this endpoint type has an InetAddress address type and thus ip() is valid - */ - ZT_INLINE bool isInetAddr() const noexcept - { - switch (this->type) { - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return true; - default: - return false; - } - } + /** + * @return True if this endpoint type has an InetAddress address type and thus ip() is valid + */ + ZT_INLINE bool isInetAddr() const noexcept + { + switch (this->type) { + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return true; + default: + return false; + } + } - /** - * Check whether this endpoint's address is the same as another. - * - * Right now this checks whether IPs are equal if both are IP based endpoints. - * Otherwise it checks for simple equality. - * - * @param ep Endpoint to check - * @return True if endpoints seem to refer to the same address/host - */ - ZT_INLINE bool isSameAddress(const Endpoint &ep) const noexcept - { - switch (this->type) { - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - switch (ep.type) { - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return ip().ipsEqual(ep.ip()); - default: - break; - } - break; - default: - break; - } - return (*this) == ep; - } + /** + * Check whether this endpoint's address is the same as another. + * + * Right now this checks whether IPs are equal if both are IP based endpoints. + * Otherwise it checks for simple equality. + * + * @param ep Endpoint to check + * @return True if endpoints seem to refer to the same address/host + */ + ZT_INLINE bool isSameAddress(const Endpoint& ep) const noexcept + { + switch (this->type) { + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + switch (ep.type) { + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return ip().ipsEqual(ep.ip()); + default: + break; + } + break; + default: + break; + } + return (*this) == ep; + } - /** - * Get InetAddress if this type uses IPv4 or IPv6 addresses (undefined otherwise) - * - * @return InetAddress instance - */ - ZT_INLINE const InetAddress &ip() const noexcept - { return asInetAddress(this->value.ss); } + /** + * Get InetAddress if this type uses IPv4 or IPv6 addresses (undefined otherwise) + * + * @return InetAddress instance + */ + ZT_INLINE const InetAddress& ip() const noexcept + { + return asInetAddress(this->value.ss); + } - /** - * Get MAC if this is an Ethernet, WiFi direct, or Bluetooth type (undefined otherwise) - * - * @return Ethernet MAC - */ - ZT_INLINE MAC eth() const noexcept - { return MAC(this->value.mac); } + /** + * Get MAC if this is an Ethernet, WiFi direct, or Bluetooth type (undefined otherwise) + * + * @return Ethernet MAC + */ + ZT_INLINE MAC eth() const noexcept + { + return MAC(this->value.mac); + } - /** - * Get fingerprint if this is a ZeroTier endpoint type (undefined otherwise) - * - * @return ZeroTier fingerprint - */ - ZT_INLINE Fingerprint zt() const noexcept - { return Fingerprint(this->value.fp); } + /** + * Get fingerprint if this is a ZeroTier endpoint type (undefined otherwise) + * + * @return ZeroTier fingerprint + */ + ZT_INLINE Fingerprint zt() const noexcept + { + return Fingerprint(this->value.fp); + } - ZT_INLINE unsigned long hashCode() const noexcept - { - switch (this->type) { - default: - return 1; - case ZT_ENDPOINT_TYPE_ZEROTIER: - return (unsigned long)this->value.fp.address; - case ZT_ENDPOINT_TYPE_ETHERNET: - case ZT_ENDPOINT_TYPE_WIFI_DIRECT: - case ZT_ENDPOINT_TYPE_BLUETOOTH: - return (unsigned long)Utils::hash64(this->value.mac); - case ZT_ENDPOINT_TYPE_IP: - case ZT_ENDPOINT_TYPE_IP_UDP: - case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_TCP_WS: - return ip().hashCode(); - } - } + ZT_INLINE unsigned long hashCode() const noexcept + { + switch (this->type) { + default: + return 1; + case ZT_ENDPOINT_TYPE_ZEROTIER: + return (unsigned long)this->value.fp.address; + case ZT_ENDPOINT_TYPE_ETHERNET: + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: + case ZT_ENDPOINT_TYPE_BLUETOOTH: + return (unsigned long)Utils::hash64(this->value.mac); + case ZT_ENDPOINT_TYPE_IP: + case ZT_ENDPOINT_TYPE_IP_UDP: + case ZT_ENDPOINT_TYPE_IP_TCP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: + return ip().hashCode(); + } + } - char *toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept; + char* toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept; - ZT_INLINE String toString() const - { - char tmp[ZT_ENDPOINT_STRING_SIZE_MAX]; - return String(toString(tmp)); - } + ZT_INLINE String toString() const + { + char tmp[ZT_ENDPOINT_STRING_SIZE_MAX]; + return String(toString(tmp)); + } - bool fromString(const char *s) noexcept; + bool fromString(const char* s) noexcept; - static constexpr int marshalSizeMax() noexcept - { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_ENDPOINT_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept; + int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept; - int unmarshal(const uint8_t *restrict data, int len) noexcept; + int unmarshal(const uint8_t* restrict data, int len) noexcept; - bool operator==(const Endpoint &ep) const noexcept; + bool operator==(const Endpoint& ep) const noexcept; - ZT_INLINE bool operator!=(const Endpoint &ep) const noexcept - { return !((*this) == ep); } + ZT_INLINE bool operator!=(const Endpoint& ep) const noexcept + { + return ! ((*this) == ep); + } - bool operator<(const Endpoint &ep) const noexcept; + bool operator<(const Endpoint& ep) const noexcept; - ZT_INLINE bool operator>(const Endpoint &ep) const noexcept - { return (ep < *this); } + ZT_INLINE bool operator>(const Endpoint& ep) const noexcept + { + return (ep < *this); + } - ZT_INLINE bool operator<=(const Endpoint &ep) const noexcept - { return !(ep < *this); } + ZT_INLINE bool operator<=(const Endpoint& ep) const noexcept + { + return ! (ep < *this); + } - ZT_INLINE bool operator>=(const Endpoint &ep) const noexcept - { return !(*this < ep); } + ZT_INLINE bool operator>=(const Endpoint& ep) const noexcept + { + return ! (*this < ep); + } }; static_assert(sizeof(Endpoint) == sizeof(ZT_Endpoint), "size mismatch"); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Expect.hpp b/core/Expect.hpp index c6d335003..728c43ad0 100644 --- a/core/Expect.hpp +++ b/core/Expect.hpp @@ -36,41 +36,50 @@ namespace ZeroTier { /** * Tracker for expected OK replies to packet IDs of sent packets */ -class Expect -{ -public: - ZT_INLINE Expect() : - m_packetIdSent() - {} +class Expect { + public: + ZT_INLINE Expect() : m_packetIdSent() + { + } - /** - * Called by other code when something is sending a packet that could potentially receive an OK response - * - * @param packetId Packet ID of packet being sent (be sure it's post-armor()) - * @param now Current time - */ - ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept - { m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] = (uint32_t)(now / ZT_EXPECT_TTL); } + /** + * Called by other code when something is sending a packet that could potentially receive an OK response + * + * @param packetId Packet ID of packet being sent (be sure it's post-armor()) + * @param now Current time + */ + ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept + { + m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] = + (uint32_t)(now / ZT_EXPECT_TTL); + } - /** - * Check if an OK is expected and if so reset the corresponding bucket. - * - * This means this call mutates the state. If it returns true, it will - * subsequently return false. This is to filter OKs against replays or - * responses to queries we did not send. - * - * @param inRePacketId In-re packet ID we're expecting - * @param now Current time - * @return True if we're expecting a reply (and a reset occurred) - */ - ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept - { return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1); } + /** + * Check if an OK is expected and if so reset the corresponding bucket. + * + * This means this call mutates the state. If it returns true, it will + * subsequently return false. This is to filter OKs against replays or + * responses to queries we did not send. + * + * @param inRePacketId In-re packet ID we're expecting + * @param now Current time + * @return True if we're expecting a reply (and a reset occurred) + */ + ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept + { + return ( + ((now / ZT_EXPECT_TTL) + - (int64_t) + m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] + .exchange(0)) + <= 1); + } -private: - // Each bucket contains a timestamp in units of the max expect duration. - std::atomic< uint32_t > m_packetIdSent[ZT_EXPECT_BUCKETS]; + private: + // Each bucket contains a timestamp in units of the max expect duration. + std::atomic m_packetIdSent[ZT_EXPECT_BUCKETS]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/FCV.hpp b/core/FCV.hpp index ebac2f458..1e6739174 100644 --- a/core/FCV.hpp +++ b/core/FCV.hpp @@ -16,8 +16,8 @@ #include "Constants.hpp" -#include #include +#include #include #include @@ -32,272 +32,305 @@ namespace ZeroTier { * @tparam T Type to contain * @tparam C Maximum capacity of vector */ -template< typename T, unsigned int C > -class FCV -{ -public: - typedef T *iterator; - typedef const T *const_iterator; +template class FCV { + public: + typedef T* iterator; + typedef const T* const_iterator; - ZT_INLINE FCV() noexcept: _s(0) - {} + ZT_INLINE FCV() noexcept : _s(0) + { + } - ZT_INLINE FCV(const FCV &v) : _s(0) - { *this = v; } + ZT_INLINE FCV(const FCV& v) : _s(0) + { + *this = v; + } - ZT_INLINE FCV(const T *const contents, const unsigned int len) : - _s(len) - { - const unsigned int l = std::min(len, C); - for (unsigned int i = 0; i < l; ++i) - new(reinterpret_cast(_m) + i) T(contents[i]); - } + ZT_INLINE FCV(const T* const contents, const unsigned int len) : _s(len) + { + const unsigned int l = std::min(len, C); + for (unsigned int i = 0; i < l; ++i) + new (reinterpret_cast(_m) + i) T(contents[i]); + } - template< typename I > - ZT_INLINE FCV(I i, I end) : - _s(0) - { - while (i != end) { - push_back(*i); - ++i; - } - } + template ZT_INLINE FCV(I i, I end) : _s(0) + { + while (i != end) { + push_back(*i); + ++i; + } + } - ZT_INLINE ~FCV() - { this->clear(); } + ZT_INLINE ~FCV() + { + this->clear(); + } - ZT_INLINE FCV &operator=(const FCV &v) - { - if (likely(&v != this)) { - this->clear(); - const unsigned int s = v._s; - _s = s; - for (unsigned int i = 0; i < s; ++i) - new(reinterpret_cast(_m) + i) T(*(reinterpret_cast(v._m) + i)); - } - return *this; - } + ZT_INLINE FCV& operator=(const FCV& v) + { + if (likely(&v != this)) { + this->clear(); + const unsigned int s = v._s; + _s = s; + for (unsigned int i = 0; i < s; ++i) + new (reinterpret_cast(_m) + i) T(*(reinterpret_cast(v._m) + i)); + } + return *this; + } - /** - * Clear this vector, destroying all content objects - */ - ZT_INLINE void clear() - { - const unsigned int s = _s; - _s = 0; - for (unsigned int i = 0; i < s; ++i) - (reinterpret_cast(_m) + i)->~T(); - } + /** + * Clear this vector, destroying all content objects + */ + ZT_INLINE void clear() + { + const unsigned int s = _s; + _s = 0; + for (unsigned int i = 0; i < s; ++i) + (reinterpret_cast(_m) + i)->~T(); + } - /** - * Move contents from this vector to another and clear this vector. - * - * @param v Target vector - */ - ZT_INLINE void unsafeMoveTo(FCV &v) noexcept - { - Utils::copy(v._m, _m, (v._s = _s) * sizeof(T)); - _s = 0; - } + /** + * Move contents from this vector to another and clear this vector. + * + * @param v Target vector + */ + ZT_INLINE void unsafeMoveTo(FCV& v) noexcept + { + Utils::copy(v._m, _m, (v._s = _s) * sizeof(T)); + _s = 0; + } - ZT_INLINE iterator begin() noexcept - { return reinterpret_cast(_m); } + ZT_INLINE iterator begin() noexcept + { + return reinterpret_cast(_m); + } - ZT_INLINE iterator end() noexcept - { return reinterpret_cast(_m) + _s; } + ZT_INLINE iterator end() noexcept + { + return reinterpret_cast(_m) + _s; + } - ZT_INLINE const_iterator begin() const noexcept - { return reinterpret_cast(_m); } + ZT_INLINE const_iterator begin() const noexcept + { + return reinterpret_cast(_m); + } - ZT_INLINE const_iterator end() const noexcept - { return reinterpret_cast(_m) + _s; } + ZT_INLINE const_iterator end() const noexcept + { + return reinterpret_cast(_m) + _s; + } - ZT_INLINE T &operator[](const unsigned int i) - { - if (likely(i < _s)) - return reinterpret_cast(_m)[i]; - throw Utils::OutOfRangeException; - } + ZT_INLINE T& operator[](const unsigned int i) + { + if (likely(i < _s)) + return reinterpret_cast(_m)[i]; + throw Utils::OutOfRangeException; + } - ZT_INLINE const T &operator[](const unsigned int i) const - { - if (likely(i < _s)) - return reinterpret_cast(_m)[i]; - throw Utils::OutOfRangeException; - } + ZT_INLINE const T& operator[](const unsigned int i) const + { + if (likely(i < _s)) + return reinterpret_cast(_m)[i]; + throw Utils::OutOfRangeException; + } - static constexpr unsigned int capacity() noexcept - { return C; } + static constexpr unsigned int capacity() noexcept + { + return C; + } - ZT_INLINE unsigned int size() const noexcept - { return _s; } + ZT_INLINE unsigned int size() const noexcept + { + return _s; + } - ZT_INLINE bool empty() const noexcept - { return (_s == 0); } + ZT_INLINE bool empty() const noexcept + { + return (_s == 0); + } - ZT_INLINE T *data() noexcept - { return reinterpret_cast(_m); } + ZT_INLINE T* data() noexcept + { + return reinterpret_cast(_m); + } - ZT_INLINE const T *data() const noexcept - { return reinterpret_cast(_m); } + ZT_INLINE const T* data() const noexcept + { + return reinterpret_cast(_m); + } - /** - * Push a value onto the back of this vector - * - * If the vector is at capacity this silently fails. - * - * @param v Value to push - */ - ZT_INLINE void push_back(const T &v) - { - if (likely(_s < C)) - new(reinterpret_cast(_m) + _s++) T(v); - else throw Utils::OutOfRangeException; - } + /** + * Push a value onto the back of this vector + * + * If the vector is at capacity this silently fails. + * + * @param v Value to push + */ + ZT_INLINE void push_back(const T& v) + { + if (likely(_s < C)) + new (reinterpret_cast(_m) + _s++) T(v); + else + throw Utils::OutOfRangeException; + } - /** - * Push new default value or return last in vector if full. - * - * @return Reference to new item - */ - ZT_INLINE T &push() - { - if (likely(_s < C)) { - return *(new(reinterpret_cast(_m) + _s++) T()); - } else { - return *(reinterpret_cast(_m) + (C - 1)); - } - } + /** + * Push new default value or return last in vector if full. + * + * @return Reference to new item + */ + ZT_INLINE T& push() + { + if (likely(_s < C)) { + return *(new (reinterpret_cast(_m) + _s++) T()); + } + else { + return *(reinterpret_cast(_m) + (C - 1)); + } + } - /** - * Push new default value or replace and return last in vector if full. - * - * @return Reference to new item - */ - ZT_INLINE T &push(const T &v) - { - if (likely(_s < C)) { - return *(new(reinterpret_cast(_m) + _s++) T(v)); - } else { - T &tmp = *(reinterpret_cast(_m) + (C - 1)); - tmp = v; - return tmp; - } - } + /** + * Push new default value or replace and return last in vector if full. + * + * @return Reference to new item + */ + ZT_INLINE T& push(const T& v) + { + if (likely(_s < C)) { + return *(new (reinterpret_cast(_m) + _s++) T(v)); + } + else { + T& tmp = *(reinterpret_cast(_m) + (C - 1)); + tmp = v; + return tmp; + } + } - /** - * Remove the last element if this vector is not empty - */ - ZT_INLINE void pop_back() - { - if (likely(_s != 0)) - (reinterpret_cast(_m) + --_s)->~T(); - } + /** + * Remove the last element if this vector is not empty + */ + ZT_INLINE void pop_back() + { + if (likely(_s != 0)) + (reinterpret_cast(_m) + --_s)->~T(); + } - /** - * Resize vector - * - * @param ns New size (clipped to C if larger than capacity) - */ - ZT_INLINE void resize(unsigned int ns) - { - if (unlikely(ns > C)) - throw Utils::OutOfRangeException; - unsigned int s = _s; - while (s < ns) - new(reinterpret_cast(_m) + s++) T(); - while (s > ns) - (reinterpret_cast(_m) + --s)->~T(); - _s = s; - } + /** + * Resize vector + * + * @param ns New size (clipped to C if larger than capacity) + */ + ZT_INLINE void resize(unsigned int ns) + { + if (unlikely(ns > C)) + throw Utils::OutOfRangeException; + unsigned int s = _s; + while (s < ns) + new (reinterpret_cast(_m) + s++) T(); + while (s > ns) + (reinterpret_cast(_m) + --s)->~T(); + _s = s; + } - /** - * Set the size of this vector without otherwise changing anything - * - * @param ns New size - */ - ZT_INLINE void unsafeSetSize(unsigned int ns) - { _s = ns; } + /** + * Set the size of this vector without otherwise changing anything + * + * @param ns New size + */ + ZT_INLINE void unsafeSetSize(unsigned int ns) + { + _s = ns; + } - /** - * This is a bounds checked auto-resizing variant of the [] operator - * - * If 'i' is out of bounds vs the current size of the vector, the vector is - * resized. If that size would exceed C (capacity), 'i' is clipped to C-1. - * - * @param i Index to obtain as a reference, resizing if needed - * @return Reference to value at this index - */ - ZT_INLINE T &at(unsigned int i) - { - if (i >= _s) { - if (unlikely(i >= C)) - i = C - 1; - do { - new(reinterpret_cast(_m) + _s++) T(); - } while (i >= _s); - } - return *(reinterpret_cast(_m) + i); - } + /** + * This is a bounds checked auto-resizing variant of the [] operator + * + * If 'i' is out of bounds vs the current size of the vector, the vector is + * resized. If that size would exceed C (capacity), 'i' is clipped to C-1. + * + * @param i Index to obtain as a reference, resizing if needed + * @return Reference to value at this index + */ + ZT_INLINE T& at(unsigned int i) + { + if (i >= _s) { + if (unlikely(i >= C)) + i = C - 1; + do { + new (reinterpret_cast(_m) + _s++) T(); + } while (i >= _s); + } + return *(reinterpret_cast(_m) + i); + } - /** - * Assign this vector's contents from a range of pointers or iterators - * - * If the range is larger than C it is truncated at C. - * - * @tparam X Inferred type of interators or pointers - * @param start Starting iterator - * @param end Ending iterator (must be greater than start) - */ - template< typename X > - ZT_INLINE void assign(X start, const X &end) - { - const int l = std::min((int)std::distance(start, end), (int)C); - if (l > 0) { - this->resize((unsigned int)l); - for (int i = 0; i < l; ++i) - reinterpret_cast(_m)[i] = *(start++); - } else { - this->clear(); - } - } + /** + * Assign this vector's contents from a range of pointers or iterators + * + * If the range is larger than C it is truncated at C. + * + * @tparam X Inferred type of interators or pointers + * @param start Starting iterator + * @param end Ending iterator (must be greater than start) + */ + template ZT_INLINE void assign(X start, const X& end) + { + const int l = std::min((int)std::distance(start, end), (int)C); + if (l > 0) { + this->resize((unsigned int)l); + for (int i = 0; i < l; ++i) + reinterpret_cast(_m)[i] = *(start++); + } + else { + this->clear(); + } + } - ZT_INLINE bool operator==(const FCV &v) const noexcept - { - if (_s == v._s) { - for (unsigned int i = 0; i < _s; ++i) { - if (!(*(reinterpret_cast(_m) + i) == *(reinterpret_cast(v._m) + i))) - return false; - } - return true; - } - return false; - } + ZT_INLINE bool operator==(const FCV& v) const noexcept + { + if (_s == v._s) { + for (unsigned int i = 0; i < _s; ++i) { + if (! (*(reinterpret_cast(_m) + i) == *(reinterpret_cast(v._m) + i))) + return false; + } + return true; + } + return false; + } - ZT_INLINE bool operator!=(const FCV &v) const noexcept - { return *this != v; } + ZT_INLINE bool operator!=(const FCV& v) const noexcept + { + return *this != v; + } - ZT_INLINE bool operator<(const FCV &v) const noexcept - { return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); } + ZT_INLINE bool operator<(const FCV& v) const noexcept + { + return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); + } - ZT_INLINE bool operator>(const FCV &v) const noexcept - { return (v < *this); } + ZT_INLINE bool operator>(const FCV& v) const noexcept + { + return (v < *this); + } - ZT_INLINE bool operator<=(const FCV &v) const noexcept - { return v >= *this; } + ZT_INLINE bool operator<=(const FCV& v) const noexcept + { + return v >= *this; + } - ZT_INLINE bool operator>=(const FCV &v) const noexcept - { return *this >= v; } + ZT_INLINE bool operator>=(const FCV& v) const noexcept + { + return *this >= v; + } -private: + private: #ifdef _MSC_VER - uint8_t _m[sizeof(T) * C]; + uint8_t _m[sizeof(T) * C]; #else - __attribute__((aligned(16))) uint8_t _m[sizeof(T) * C]; + __attribute__((aligned(16))) uint8_t _m[sizeof(T) * C]; #endif - unsigned int _s; + unsigned int _s; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Fingerprint.hpp b/core/Fingerprint.hpp index 89aed3534..627dfe43c 100644 --- a/core/Fingerprint.hpp +++ b/core/Fingerprint.hpp @@ -14,13 +14,13 @@ #ifndef ZT_FINGERPRINT_HPP #define ZT_FINGERPRINT_HPP +#include "Address.hpp" #include "Constants.hpp" #include "TriviallyCopyable.hpp" -#include "Address.hpp" #include "Utils.hpp" #define ZT_FINGERPRINT_STRING_SIZE_MAX 128 -#define ZT_FINGERPRINT_MARSHAL_SIZE 53 +#define ZT_FINGERPRINT_MARSHAL_SIZE 53 namespace ZeroTier { @@ -30,117 +30,152 @@ namespace ZeroTier { * This is the same size as ZT_Fingerprint and should be cast-able back and forth. * This is checked in Tests.cpp. */ -class Fingerprint : public ZT_Fingerprint, public TriviallyCopyable -{ -public: - ZT_INLINE Fingerprint() noexcept - { memoryZero(this); } +class Fingerprint + : public ZT_Fingerprint + , public TriviallyCopyable { + public: + ZT_INLINE Fingerprint() noexcept + { + memoryZero(this); + } - ZT_INLINE Fingerprint(const ZT_Fingerprint &fp) noexcept - { Utils::copy< sizeof(ZT_Fingerprint) >(this, &fp); } + ZT_INLINE Fingerprint(const ZT_Fingerprint& fp) noexcept + { + Utils::copy(this, &fp); + } - /** - * @return True if hash is not all zero (missing/unspecified) - */ - ZT_INLINE bool haveHash() const noexcept - { return (!Utils::allZero(this->hash, ZT_FINGERPRINT_HASH_SIZE)); } + /** + * @return True if hash is not all zero (missing/unspecified) + */ + ZT_INLINE bool haveHash() const noexcept + { + return (! Utils::allZero(this->hash, ZT_FINGERPRINT_HASH_SIZE)); + } - /** - * Get a base32-encoded representation of this fingerprint - * - * @param s Base32 string - */ - ZT_INLINE char *toString(char s[ZT_FINGERPRINT_STRING_SIZE_MAX]) const noexcept - { - Address(this->address).toString(s); - if (haveHash()) { - s[ZT_ADDRESS_LENGTH_HEX] = '-'; - Utils::b32e(this->hash, ZT_FINGERPRINT_HASH_SIZE, s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); - } - return s; - } + /** + * Get a base32-encoded representation of this fingerprint + * + * @param s Base32 string + */ + ZT_INLINE char* toString(char s[ZT_FINGERPRINT_STRING_SIZE_MAX]) const noexcept + { + Address(this->address).toString(s); + if (haveHash()) { + s[ZT_ADDRESS_LENGTH_HEX] = '-'; + Utils::b32e( + this->hash, + ZT_FINGERPRINT_HASH_SIZE, + s + (ZT_ADDRESS_LENGTH_HEX + 1), + ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); + } + return s; + } - ZT_INLINE String toString() const - { - char tmp[ZT_FINGERPRINT_STRING_SIZE_MAX]; - return String(toString(tmp)); - } + ZT_INLINE String toString() const + { + char tmp[ZT_FINGERPRINT_STRING_SIZE_MAX]; + return String(toString(tmp)); + } - /** - * Set this fingerprint to a base32-encoded string - * - * @param s String to decode - * @return True if string appears to be valid and of the proper length (no other checking is done) - */ - ZT_INLINE bool fromString(const char *const s) noexcept - { - if (!s) - return false; - const int l = (int)strlen(s); - if (l < ZT_ADDRESS_LENGTH_HEX) - return false; - char a[ZT_ADDRESS_LENGTH_HEX + 1]; - Utils::copy< ZT_ADDRESS_LENGTH_HEX >(a, s); - a[ZT_ADDRESS_LENGTH_HEX] = 0; - this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK; - if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) { - if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) != ZT_FINGERPRINT_HASH_SIZE) - return false; - } else { - Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(this->hash); - } - return true; - } + /** + * Set this fingerprint to a base32-encoded string + * + * @param s String to decode + * @return True if string appears to be valid and of the proper length (no other checking is done) + */ + ZT_INLINE bool fromString(const char* const s) noexcept + { + if (! s) + return false; + const int l = (int)strlen(s); + if (l < ZT_ADDRESS_LENGTH_HEX) + return false; + char a[ZT_ADDRESS_LENGTH_HEX + 1]; + Utils::copy(a, s); + a[ZT_ADDRESS_LENGTH_HEX] = 0; + this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK; + if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) { + if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) + != ZT_FINGERPRINT_HASH_SIZE) + return false; + } + else { + Utils::zero(this->hash); + } + return true; + } - ZT_INLINE void zero() noexcept - { memoryZero(this); } + ZT_INLINE void zero() noexcept + { + memoryZero(this); + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)this->address; } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)this->address; + } - ZT_INLINE operator bool() const noexcept - { return this->address != 0; } + ZT_INLINE operator bool() const noexcept + { + return this->address != 0; + } - static constexpr int marshalSizeMax() noexcept - { return ZT_FINGERPRINT_MARSHAL_SIZE; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_FINGERPRINT_MARSHAL_SIZE; + } - ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept - { - Address(this->address).copyTo(data); - Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(data + ZT_ADDRESS_LENGTH, this->hash); - return ZT_FINGERPRINT_MARSHAL_SIZE; - } + ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept + { + Address(this->address).copyTo(data); + Utils::copy(data + ZT_ADDRESS_LENGTH, this->hash); + return ZT_FINGERPRINT_MARSHAL_SIZE; + } - ZT_INLINE int unmarshal(const uint8_t *const data, int len) noexcept - { - if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE)) - return -1; - this->address = Address(data); - Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(hash, data + ZT_ADDRESS_LENGTH); - return ZT_FINGERPRINT_MARSHAL_SIZE; - } + ZT_INLINE int unmarshal(const uint8_t* const data, int len) noexcept + { + if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE)) + return -1; + this->address = Address(data); + Utils::copy(hash, data + ZT_ADDRESS_LENGTH); + return ZT_FINGERPRINT_MARSHAL_SIZE; + } - ZT_INLINE bool operator==(const ZT_Fingerprint &h) const noexcept - { return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); } + ZT_INLINE bool operator==(const ZT_Fingerprint& h) const noexcept + { + return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); + } - ZT_INLINE bool operator!=(const ZT_Fingerprint &h) const noexcept - { return !(*this == h); } + ZT_INLINE bool operator!=(const ZT_Fingerprint& h) const noexcept + { + return ! (*this == h); + } - ZT_INLINE bool operator<(const ZT_Fingerprint &h) const noexcept - { return ((this->address < h.address) || ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); } + ZT_INLINE bool operator<(const ZT_Fingerprint& h) const noexcept + { + return ( + (this->address < h.address) + || ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); + } - ZT_INLINE bool operator>(const ZT_Fingerprint &h) const noexcept - { return (*reinterpret_cast(&h) < *this); } + ZT_INLINE bool operator>(const ZT_Fingerprint& h) const noexcept + { + return (*reinterpret_cast(&h) < *this); + } - ZT_INLINE bool operator<=(const ZT_Fingerprint &h) const noexcept - { return !(*reinterpret_cast(&h) < *this); } + ZT_INLINE bool operator<=(const ZT_Fingerprint& h) const noexcept + { + return ! (*reinterpret_cast(&h) < *this); + } - ZT_INLINE bool operator>=(const ZT_Fingerprint &h) const noexcept - { return !(*this < h); } + ZT_INLINE bool operator>=(const ZT_Fingerprint& h) const noexcept + { + return ! (*this < h); + } }; static_assert(sizeof(Fingerprint) == sizeof(ZT_Fingerprint), "size mismatch"); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Identity.cpp b/core/Identity.cpp index 3930d09d6..666268b68 100644 --- a/core/Identity.cpp +++ b/core/Identity.cpp @@ -11,13 +11,14 @@ */ /****/ -#include "Constants.hpp" #include "Identity.hpp" + +#include "Constants.hpp" +#include "Endpoint.hpp" +#include "MIMC52.hpp" #include "SHA512.hpp" #include "Salsa20.hpp" #include "Utils.hpp" -#include "Endpoint.hpp" -#include "MIMC52.hpp" #include #include @@ -29,479 +30,511 @@ namespace { // This is the memory-intensive hash function used to compute v0 identities from v0 public keys. #define ZT_V0_IDENTITY_GEN_MEMORY 2097152 -void identityV0ProofOfWorkFrankenhash(const void *const restrict c25519CombinedPublicKey, void *const restrict digest, void *const restrict genmem) noexcept +void identityV0ProofOfWorkFrankenhash( + const void* const restrict c25519CombinedPublicKey, + void* const restrict digest, + void* const restrict genmem) noexcept { - // Digest publicKey[] to obtain initial digest - SHA512(digest, c25519CombinedPublicKey, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE); + // Digest publicKey[] to obtain initial digest + SHA512(digest, c25519CombinedPublicKey, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE); - // Initialize genmem[] using Salsa20 in a CBC-like configuration since - // ordinary Salsa20 is randomly seek-able. This is good for a cipher - // but is not what we want for sequential memory-hardness. - Utils::zero< ZT_V0_IDENTITY_GEN_MEMORY >(genmem); - Salsa20 s20(digest, (char *)digest + 32); - s20.crypt20((char *)genmem, (char *)genmem, 64); - for (unsigned long i = 64; i < ZT_V0_IDENTITY_GEN_MEMORY; i += 64) { - unsigned long k = i - 64; - *((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k)); - *((uint64_t *)((char *)genmem + i + 8)) = *((uint64_t *)((char *)genmem + k + 8)); - *((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16)); - *((uint64_t *)((char *)genmem + i + 24)) = *((uint64_t *)((char *)genmem + k + 24)); - *((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32)); - *((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40)); - *((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48)); - *((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56)); - s20.crypt20((char *)genmem + i, (char *)genmem + i, 64); - } + // Initialize genmem[] using Salsa20 in a CBC-like configuration since + // ordinary Salsa20 is randomly seek-able. This is good for a cipher + // but is not what we want for sequential memory-hardness. + Utils::zero(genmem); + Salsa20 s20(digest, (char*)digest + 32); + s20.crypt20((char*)genmem, (char*)genmem, 64); + for (unsigned long i = 64; i < ZT_V0_IDENTITY_GEN_MEMORY; i += 64) { + unsigned long k = i - 64; + *((uint64_t*)((char*)genmem + i)) = *((uint64_t*)((char*)genmem + k)); + *((uint64_t*)((char*)genmem + i + 8)) = *((uint64_t*)((char*)genmem + k + 8)); + *((uint64_t*)((char*)genmem + i + 16)) = *((uint64_t*)((char*)genmem + k + 16)); + *((uint64_t*)((char*)genmem + i + 24)) = *((uint64_t*)((char*)genmem + k + 24)); + *((uint64_t*)((char*)genmem + i + 32)) = *((uint64_t*)((char*)genmem + k + 32)); + *((uint64_t*)((char*)genmem + i + 40)) = *((uint64_t*)((char*)genmem + k + 40)); + *((uint64_t*)((char*)genmem + i + 48)) = *((uint64_t*)((char*)genmem + k + 48)); + *((uint64_t*)((char*)genmem + i + 56)) = *((uint64_t*)((char*)genmem + k + 56)); + s20.crypt20((char*)genmem + i, (char*)genmem + i, 64); + } - // Render final digest using genmem as a lookup table - for (unsigned long i = 0; i < (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) { - unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (64 / sizeof(uint64_t))); - unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t))); - uint64_t tmp = ((uint64_t *)genmem)[idx2]; - ((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1]; - ((uint64_t *)digest)[idx1] = tmp; - s20.crypt20(digest, digest, 64); - } + // Render final digest using genmem as a lookup table + for (unsigned long i = 0; i < (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) { + unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (64 / sizeof(uint64_t))); + unsigned long idx2 = + (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t))); + uint64_t tmp = ((uint64_t*)genmem)[idx2]; + ((uint64_t*)genmem)[idx2] = ((uint64_t*)digest)[idx1]; + ((uint64_t*)digest)[idx1] = tmp; + s20.crypt20(digest, digest, 64); + } } -struct identityV0ProofOfWorkCriteria -{ - ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char *restrict sb, char *restrict gm) noexcept: digest(sb), genmem(gm) - {} +struct identityV0ProofOfWorkCriteria { + ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char* restrict sb, char* restrict gm) noexcept + : digest(sb) + , genmem(gm) + { + } - ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]) const noexcept - { - identityV0ProofOfWorkFrankenhash(pub, digest, genmem); - return (digest[0] < 17); - } + ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]) const noexcept + { + identityV0ProofOfWorkFrankenhash(pub, digest, genmem); + return (digest[0] < 17); + } - unsigned char *restrict digest; - char *restrict genmem; + unsigned char* restrict digest; + char* restrict genmem; }; void v1ChallengeFromPub(const uint8_t pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE], uint64_t challenge[4]) { - // This builds a 256-bit challenge by XORing the two public keys together. This doesn't need to be - // a hash, just different for different public keys. Public keys are basically kind of hashes of - // private keys, so that's good enough. This is only used to seed a PRNG in MIMC52 for a proof of - // sequential work. It's not used for authentication beyond checking PoW. - Utils::copy< 32 >(challenge, pub + 7); - challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 40); - challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 48); - challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 56); - challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 64); - challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 72); - challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 80); - challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 88); - challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 96); - challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 104); - challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 112); + // This builds a 256-bit challenge by XORing the two public keys together. This doesn't need to be + // a hash, just different for different public keys. Public keys are basically kind of hashes of + // private keys, so that's good enough. This is only used to seed a PRNG in MIMC52 for a proof of + // sequential work. It's not used for authentication beyond checking PoW. + Utils::copy<32>(challenge, pub + 7); + challenge[0] ^= Utils::loadMachineEndian(pub + 40); + challenge[1] ^= Utils::loadMachineEndian(pub + 48); + challenge[2] ^= Utils::loadMachineEndian(pub + 56); + challenge[3] ^= Utils::loadMachineEndian(pub + 64); + challenge[0] ^= Utils::loadMachineEndian(pub + 72); + challenge[1] ^= Utils::loadMachineEndian(pub + 80); + challenge[2] ^= Utils::loadMachineEndian(pub + 88); + challenge[3] ^= Utils::loadMachineEndian(pub + 96); + challenge[0] ^= Utils::loadMachineEndian(pub + 104); + challenge[1] ^= Utils::loadMachineEndian(pub + 112); } -} // anonymous namespace +} // anonymous namespace const Identity Identity::NIL; bool Identity::generate(const Type t) { - m_type = t; - m_hasPrivate = true; + m_type = t; + m_hasPrivate = true; - switch (t) { + switch (t) { + case C25519: { + // Generate C25519/Ed25519 key pair whose hash satisfies a "hashcash" criterion and generate the + // address from the last 40 bits of this hash. This is different from the fingerprint hash for V0. + uint8_t digest[64]; + char* const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY]; + Address address; + do { + C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest, genmem), m_pub, m_priv); + address.setTo(digest + 59); + } while (address.isReserved()); + delete[] genmem; + m_fp.address = address; // address comes from PoW hash for type 0 identities + m_computeHash(); + } break; - case C25519: { - // Generate C25519/Ed25519 key pair whose hash satisfies a "hashcash" criterion and generate the - // address from the last 40 bits of this hash. This is different from the fingerprint hash for V0. - uint8_t digest[64]; - char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY]; - Address address; - do { - C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest, genmem), m_pub, m_priv); - address.setTo(digest + 59); - } while (address.isReserved()); - delete[] genmem; - m_fp.address = address; // address comes from PoW hash for type 0 identities - m_computeHash(); - } - break; + case P384: + for (;;) { + C25519::generateCombined(m_pub + 7, m_priv); + ECC384GenerateKey( + m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, + m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); - case P384: - for (;;) { - C25519::generateCombined(m_pub + 7, m_priv); - ECC384GenerateKey(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + uint64_t challenge[4]; + v1ChallengeFromPub(m_pub, challenge); + const uint64_t proof = + MIMC52::delay(reinterpret_cast(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); + m_pub[0] = (uint8_t)(proof >> 48U); + m_pub[1] = (uint8_t)(proof >> 40U); + m_pub[2] = (uint8_t)(proof >> 32U); + m_pub[3] = (uint8_t)(proof >> 24U); + m_pub[4] = (uint8_t)(proof >> 16U); + m_pub[5] = (uint8_t)(proof >> 8U); + m_pub[6] = (uint8_t)proof; - uint64_t challenge[4]; - v1ChallengeFromPub(m_pub, challenge); - const uint64_t proof = MIMC52::delay(reinterpret_cast(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); - m_pub[0] = (uint8_t)(proof >> 48U); - m_pub[1] = (uint8_t)(proof >> 40U); - m_pub[2] = (uint8_t)(proof >> 32U); - m_pub[3] = (uint8_t)(proof >> 24U); - m_pub[4] = (uint8_t)(proof >> 16U); - m_pub[5] = (uint8_t)(proof >> 8U); - m_pub[6] = (uint8_t)proof; + m_computeHash(); + const Address addr(m_fp.hash); + if (! addr.isReserved()) { + m_fp.address = addr; + break; + } + } + break; - m_computeHash(); - const Address addr(m_fp.hash); - if (!addr.isReserved()) { - m_fp.address = addr; - break; - } - } - break; + default: + return false; + } - default: - return false; - } - - return true; + return true; } bool Identity::locallyValidate() const noexcept { - try { - if ((m_fp) && ((!Address(m_fp.address).isReserved()))) { - switch (m_type) { + try { + if ((m_fp) && ((! Address(m_fp.address).isReserved()))) { + switch (m_type) { + case C25519: { + uint8_t digest[64]; + char* const genmem = (char*)malloc(ZT_V0_IDENTITY_GEN_MEMORY); + if (! genmem) + return false; + identityV0ProofOfWorkFrankenhash(m_pub, digest, genmem); + free(genmem); + return ((Address(digest + 59) == m_fp.address) && (digest[0] < 17)); + } - case C25519: { - uint8_t digest[64]; - char *const genmem = (char *)malloc(ZT_V0_IDENTITY_GEN_MEMORY); - if (!genmem) - return false; - identityV0ProofOfWorkFrankenhash(m_pub, digest, genmem); - free(genmem); - return ((Address(digest + 59) == m_fp.address) && (digest[0] < 17)); - } - - case P384: - if (Address(m_fp.hash) == m_fp.address) { - uint64_t challenge[4]; - v1ChallengeFromPub(m_pub, challenge); - return MIMC52::verify(reinterpret_cast(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, ((uint64_t)m_pub[0] << 48U) | ((uint64_t)m_pub[1] << 40U) | ((uint64_t)m_pub[2] << 32U) | ((uint64_t)m_pub[3] << 24U) | ((uint64_t)m_pub[4] << 16U) | ((uint64_t)m_pub[5] << 8U) | (uint64_t)m_pub[6]); - } - return false; - - } - } - } catch (...) {} - return false; + case P384: + if (Address(m_fp.hash) == m_fp.address) { + uint64_t challenge[4]; + v1ChallengeFromPub(m_pub, challenge); + return MIMC52::verify( + reinterpret_cast(challenge), + ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, + ((uint64_t)m_pub[0] << 48U) | ((uint64_t)m_pub[1] << 40U) | ((uint64_t)m_pub[2] << 32U) + | ((uint64_t)m_pub[3] << 24U) | ((uint64_t)m_pub[4] << 16U) | ((uint64_t)m_pub[5] << 8U) + | (uint64_t)m_pub[6]); + } + return false; + } + } + } + catch (...) { + } + return false; } void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const { - if (m_hasPrivate) { - switch (m_type) { + if (m_hasPrivate) { + switch (m_type) { + case C25519: + SHA384(h, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + return; - case C25519: - SHA384(h, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); - return; - - case P384: - SHA384(h, m_pub, sizeof(m_pub), m_priv, sizeof(m_priv)); - return; - - } - } - Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(h); + case P384: + SHA384(h, m_pub, sizeof(m_pub), m_priv, sizeof(m_priv)); + return; + } + } + Utils::zero(h); } -unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsigned int siglen) const +unsigned int Identity::sign(const void* data, unsigned int len, void* sig, unsigned int siglen) const { - if (m_hasPrivate) { - switch (m_type) { + if (m_hasPrivate) { + switch (m_type) { + case C25519: + if (siglen >= ZT_C25519_SIGNATURE_LEN) { + C25519::sign(m_priv, m_pub, data, len, sig); + return ZT_C25519_SIGNATURE_LEN; + } + break; - case C25519: - if (siglen >= ZT_C25519_SIGNATURE_LEN) { - C25519::sign(m_priv, m_pub, data, len, sig); - return ZT_C25519_SIGNATURE_LEN; - } - break; - - case P384: - if (siglen >= ZT_ECC384_SIGNATURE_SIZE) { - static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!"); - uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; - SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t *)sig); - return ZT_ECC384_SIGNATURE_SIZE; - } - break; - - } - } - return 0; + case P384: + if (siglen >= ZT_ECC384_SIGNATURE_SIZE) { + static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!"); + uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; + SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); + ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t*)sig); + return ZT_ECC384_SIGNATURE_SIZE; + } + break; + } + } + return 0; } -bool Identity::verify(const void *data, unsigned int len, const void *sig, unsigned int siglen) const +bool Identity::verify(const void* data, unsigned int len, const void* sig, unsigned int siglen) const { - switch (m_type) { + switch (m_type) { + case C25519: + return C25519::verify(m_pub, data, len, sig, siglen); - case C25519: - return C25519::verify(m_pub, data, len, sig, siglen); - - case P384: - if (siglen == ZT_ECC384_SIGNATURE_SIZE) { - uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; - SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - return ECC384ECDSAVerify(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t *)sig); - } - break; - - } - return false; + case P384: + if (siglen == ZT_ECC384_SIGNATURE_SIZE) { + uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; + SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); + return ECC384ECDSAVerify(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t*)sig); + } + break; + } + return false; } -bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const +bool Identity::agree(const Identity& id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const { - uint8_t rawkey[128], h[64]; - if (m_hasPrivate) { - if ((m_type == C25519) || (id.m_type == C25519)) { - // If we are a C25519 key we can agree with another C25519 key or with only the - // C25519 portion of a type 1 P-384 key. - C25519::agree(m_priv, id.m_pub, rawkey); - SHA512(h, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE); - Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(key, h); - return true; - } else if ((m_type == P384) && (id.m_type == P384)) { - // For another P384 identity we execute DH agreement with BOTH keys and then - // hash the results together. For those (cough FIPS cough) who only consider - // P384 to be kosher, the C25519 secret can be considered a "salt" - // or something. For those who don't trust P384 this means the privacy of - // your traffic is also protected by C25519. - C25519::agree(m_priv, id.m_pub, rawkey); - ECC384ECDH(id.m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE); - SHA384(key, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE); - return true; - } - } - return false; + uint8_t rawkey[128], h[64]; + if (m_hasPrivate) { + if ((m_type == C25519) || (id.m_type == C25519)) { + // If we are a C25519 key we can agree with another C25519 key or with only the + // C25519 portion of a type 1 P-384 key. + C25519::agree(m_priv, id.m_pub, rawkey); + SHA512(h, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE); + Utils::copy(key, h); + return true; + } + else if ((m_type == P384) && (id.m_type == P384)) { + // For another P384 identity we execute DH agreement with BOTH keys and then + // hash the results together. For those (cough FIPS cough) who only consider + // P384 to be kosher, the C25519 secret can be considered a "salt" + // or something. For those who don't trust P384 this means the privacy of + // your traffic is also protected by C25519. + C25519::agree(m_priv, id.m_pub, rawkey); + ECC384ECDH( + id.m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, + m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, + rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE); + SHA384(key, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE); + return true; + } + } + return false; } -char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const +char* Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const { - char *p = buf; - Address(m_fp.address).toString(p); - p += 10; - *(p++) = ':'; + char* p = buf; + Address(m_fp.address).toString(p); + p += 10; + *(p++) = ':'; - switch (m_type) { - case C25519: { - *(p++) = '0'; - *(p++) = ':'; - Utils::hex(m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, p); - p += ZT_C25519_COMBINED_PUBLIC_KEY_SIZE * 2; - if ((m_hasPrivate) && (includePrivate)) { - *(p++) = ':'; - Utils::hex(m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, p); - p += ZT_C25519_COMBINED_PRIVATE_KEY_SIZE * 2; - } - *p = (char)0; - return buf; - } - case P384: { - *(p++) = '1'; - *(p++) = ':'; - int el = Utils::b32e(m_pub, sizeof(m_pub), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); - if (el <= 0) return nullptr; - p += el; - if ((m_hasPrivate) && (includePrivate)) { - *(p++) = ':'; - el = Utils::b32e(m_priv, sizeof(m_priv), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); - if (el <= 0) return nullptr; - p += el; - } - *p = (char)0; - return buf; - } - default: - buf[0] = 0; - } + switch (m_type) { + case C25519: { + *(p++) = '0'; + *(p++) = ':'; + Utils::hex(m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, p); + p += ZT_C25519_COMBINED_PUBLIC_KEY_SIZE * 2; + if ((m_hasPrivate) && (includePrivate)) { + *(p++) = ':'; + Utils::hex(m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, p); + p += ZT_C25519_COMBINED_PRIVATE_KEY_SIZE * 2; + } + *p = (char)0; + return buf; + } + case P384: { + *(p++) = '1'; + *(p++) = ':'; + int el = + Utils::b32e(m_pub, sizeof(m_pub), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); + if (el <= 0) + return nullptr; + p += el; + if ((m_hasPrivate) && (includePrivate)) { + *(p++) = ':'; + el = Utils::b32e( + m_priv, + sizeof(m_priv), + p, + (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); + if (el <= 0) + return nullptr; + p += el; + } + *p = (char)0; + return buf; + } + default: + buf[0] = 0; + } - return nullptr; + return nullptr; } -bool Identity::fromString(const char *str) +bool Identity::fromString(const char* str) { - char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - memoryZero(this); - if ((!str) || (!Utils::scopy(tmp, sizeof(tmp), str))) - return false; + char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + memoryZero(this); + if ((! str) || (! Utils::scopy(tmp, sizeof(tmp), str))) + return false; - int fno = 0; - char *saveptr = nullptr; - for (char *f = Utils::stok(tmp, ":", &saveptr); ((f) && (fno < 4)); f = Utils::stok(nullptr, ":", &saveptr)) { - switch (fno++) { + int fno = 0; + char* saveptr = nullptr; + for (char* f = Utils::stok(tmp, ":", &saveptr); ((f) && (fno < 4)); f = Utils::stok(nullptr, ":", &saveptr)) { + switch (fno++) { + case 0: + m_fp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK; + if (Address(m_fp.address).isReserved()) + return false; + break; - case 0: - m_fp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK; - if (Address(m_fp.address).isReserved()) - return false; - break; + case 1: + if ((f[0] == '0') && (! f[1])) { + m_type = C25519; + } + else if ((f[0] == '1') && (! f[1])) { + m_type = P384; + } + else { + return false; + } + break; - case 1: - if ((f[0] == '0') && (!f[1])) { - m_type = C25519; - } else if ((f[0] == '1') && (!f[1])) { - m_type = P384; - } else { - return false; - } - break; + case 2: + switch (m_type) { + case C25519: + if (Utils::unhex(f, strlen(f), m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) + != ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) + return false; + break; - case 2: - switch (m_type) { + case P384: + if (Utils::b32d(f, m_pub, sizeof(m_pub)) != sizeof(m_pub)) + return false; + break; + } + break; - case C25519: - if (Utils::unhex(f, strlen(f), m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) != ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) - return false; - break; + case 3: + if (strlen(f) > 1) { + switch (m_type) { + case C25519: + if (Utils::unhex(f, strlen(f), m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) + != ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) { + return false; + } + else { + m_hasPrivate = true; + } + break; - case P384: - if (Utils::b32d(f, m_pub, sizeof(m_pub)) != sizeof(m_pub)) - return false; - break; + case P384: + if (Utils::b32d(f, m_priv, sizeof(m_priv)) != sizeof(m_priv)) { + return false; + } + else { + m_hasPrivate = true; + } + break; + } + break; + } + } + } - } - break; + if (fno < 3) + return false; - case 3: - if (strlen(f) > 1) { - switch (m_type) { - - case C25519: - if (Utils::unhex(f, strlen(f), m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) != ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) { - return false; - } else { - m_hasPrivate = true; - } - break; - - case P384: - if (Utils::b32d(f, m_priv, sizeof(m_priv)) != sizeof(m_priv)) { - return false; - } else { - m_hasPrivate = true; - } - break; - - } - break; - } - - } - } - - if (fno < 3) - return false; - - m_computeHash(); - return !((m_type == P384) && (Address(m_fp.hash) != m_fp.address)); + m_computeHash(); + return ! ((m_type == P384) && (Address(m_fp.hash) != m_fp.address)); } int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool includePrivate) const noexcept { - Address(m_fp.address).copyTo(data); - switch (m_type) { + Address(m_fp.address).copyTo(data); + switch (m_type) { + case C25519: + data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519; + Utils::copy(data + ZT_ADDRESS_LENGTH + 1, m_pub); + if ((includePrivate) && (m_hasPrivate)) { + data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; + Utils::copy( + data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1, + m_priv); + return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; + } + data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0; + return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; - case C25519: - data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519; - Utils::copy< ZT_C25519_COMBINED_PUBLIC_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1, m_pub); - if ((includePrivate) && (m_hasPrivate)) { - data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; - Utils::copy< ZT_C25519_COMBINED_PRIVATE_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1, m_priv); - return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; - } - data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0; - return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; - - case P384: - data[ZT_ADDRESS_LENGTH] = (uint8_t)P384; - Utils::copy< ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1, m_pub); - if ((includePrivate) && (m_hasPrivate)) { - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; - Utils::copy< ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1, m_priv); - return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; - } - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0; - return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1; - - } - return -1; + case P384: + data[ZT_ADDRESS_LENGTH] = (uint8_t)P384; + Utils::copy(data + ZT_ADDRESS_LENGTH + 1, m_pub); + if ((includePrivate) && (m_hasPrivate)) { + data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; + Utils::copy( + data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1, + m_priv); + return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; + } + data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0; + return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1; + } + return -1; } -int Identity::unmarshal(const uint8_t *data, const int len) noexcept +int Identity::unmarshal(const uint8_t* data, const int len) noexcept { - memoryZero(this); + memoryZero(this); - if (len < (1 + ZT_ADDRESS_LENGTH)) - return -1; - m_fp.address = Address(data); + if (len < (1 + ZT_ADDRESS_LENGTH)) + return -1; + m_fp.address = Address(data); - unsigned int privlen; - switch ((m_type = (Type)data[ZT_ADDRESS_LENGTH])) { + unsigned int privlen; + switch ((m_type = (Type)data[ZT_ADDRESS_LENGTH])) { + case C25519: + if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1)) + return -1; - case C25519: - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1)) - return -1; + Utils::copy(m_pub, data + ZT_ADDRESS_LENGTH + 1); + m_computeHash(); - Utils::copy< ZT_C25519_COMBINED_PUBLIC_KEY_SIZE >(m_pub, data + ZT_ADDRESS_LENGTH + 1); - m_computeHash(); + privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]; + if (privlen == ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) { + if (len + < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE)) + return -1; + m_hasPrivate = true; + Utils::copy( + m_priv, + data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1); + return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; + } + else if (privlen == 0) { + m_hasPrivate = false; + return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; + } + break; - privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]; - if (privlen == ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) { - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE)) - return -1; - m_hasPrivate = true; - Utils::copy< ZT_C25519_COMBINED_PRIVATE_KEY_SIZE >(m_priv, data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1); - return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; - } else if (privlen == 0) { - m_hasPrivate = false; - return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; - } - break; + case P384: + if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1)) + return -1; - case P384: - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1)) - return -1; + Utils::copy(m_pub, data + ZT_ADDRESS_LENGTH + 1); + m_computeHash(); // this sets the address for P384 + if (Address(m_fp.hash) != m_fp.address) // this sanity check is possible with V1 identities + return -1; - Utils::copy< ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE >(m_pub, data + ZT_ADDRESS_LENGTH + 1); - m_computeHash(); // this sets the address for P384 - if (Address(m_fp.hash) != m_fp.address) // this sanity check is possible with V1 identities - return -1; + privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; + if (privlen == 0) { + m_hasPrivate = false; + return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1; + } + else if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) { + if (len + < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)) + return -1; + m_hasPrivate = true; + Utils::copy( + &m_priv, + data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1); + return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; + } + break; + } - privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; - if (privlen == 0) { - m_hasPrivate = false; - return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1; - } else if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) { - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)) - return -1; - m_hasPrivate = true; - Utils::copy< ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE >(&m_priv, data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1); - return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; - } - break; - - } - - return -1; + return -1; } void Identity::m_computeHash() { - switch (m_type) { - default: - m_fp.zero(); - break; + switch (m_type) { + default: + m_fp.zero(); + break; - case C25519: - SHA384(m_fp.hash, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE); - break; + case C25519: + SHA384(m_fp.hash, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE); + break; - case P384: - SHA384(m_fp.hash, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - break; - } + case P384: + SHA384(m_fp.hash, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); + break; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Identity.hpp b/core/Identity.hpp index d9e14ca15..09976f5ff 100644 --- a/core/Identity.hpp +++ b/core/Identity.hpp @@ -14,21 +14,22 @@ #ifndef ZT_IDENTITY_HPP #define ZT_IDENTITY_HPP -#include "Constants.hpp" -#include "Utils.hpp" #include "Address.hpp" #include "C25519.hpp" -#include "SHA512.hpp" -#include "ECC384.hpp" -#include "TriviallyCopyable.hpp" -#include "Fingerprint.hpp" +#include "Constants.hpp" #include "Containers.hpp" +#include "ECC384.hpp" +#include "Fingerprint.hpp" +#include "SHA512.hpp" +#include "TriviallyCopyable.hpp" +#include "Utils.hpp" #define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024 #define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE) #define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_COMBINED_PRIVATE_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE) -#define ZT_IDENTITY_MARSHAL_SIZE_MAX (ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) -#define ZT_IDENTITY_TYPE1_MIMC52_ROUNDS 262144 +#define ZT_IDENTITY_MARSHAL_SIZE_MAX \ + (ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) +#define ZT_IDENTITY_TYPE1_MIMC52_ROUNDS 262144 namespace ZeroTier { @@ -44,225 +45,259 @@ namespace ZeroTier { * Type 1 identities are better in many ways but type 0 will remain the default until * 1.x nodes are pretty much dead in the wild. */ -class Identity : public TriviallyCopyable -{ -public: - /** - * Identity type -- numeric values of these enums are protocol constants - */ - enum Type - { - C25519 = ZT_IDENTITY_TYPE_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default) - P384 = ZT_IDENTITY_TYPE_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+) - }; +class Identity : public TriviallyCopyable { + public: + /** + * Identity type -- numeric values of these enums are protocol constants + */ + enum Type { + C25519 = ZT_IDENTITY_TYPE_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default) + P384 = ZT_IDENTITY_TYPE_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+) + }; - /** - * A nil/empty identity instance - */ - static const Identity NIL; + /** + * A nil/empty identity instance + */ + static const Identity NIL; - ZT_INLINE Identity() noexcept - { memoryZero(this); } + ZT_INLINE Identity() noexcept + { + memoryZero(this); + } - ZT_INLINE Identity(const Identity &id) noexcept - { Utils::copy< sizeof(Identity) >(this, &id); } + ZT_INLINE Identity(const Identity& id) noexcept + { + Utils::copy(this, &id); + } - /** - * Construct identity from string - * - * If the identity is not basically valid (no deep checking is done) the result will - * be a null identity. - * - * @param str Identity in canonical string format - */ - explicit ZT_INLINE Identity(const char *str) - { fromString(str); } + /** + * Construct identity from string + * + * If the identity is not basically valid (no deep checking is done) the result will + * be a null identity. + * + * @param str Identity in canonical string format + */ + explicit ZT_INLINE Identity(const char* str) + { + fromString(str); + } - ZT_INLINE ~Identity() - { Utils::burn(reinterpret_cast(&this->m_priv), sizeof(this->m_priv)); } + ZT_INLINE ~Identity() + { + Utils::burn(reinterpret_cast(&this->m_priv), sizeof(this->m_priv)); + } - ZT_INLINE Identity &operator=(const Identity &id) noexcept - { - if (likely(this != &id)) - Utils::copy< sizeof(Identity) >(this, &id); - return *this; - } + ZT_INLINE Identity& operator=(const Identity& id) noexcept + { + if (likely(this != &id)) + Utils::copy(this, &id); + return *this; + } - /** - * Set identity to NIL value (all zero) - */ - ZT_INLINE void zero() noexcept - { memoryZero(this); } + /** + * Set identity to NIL value (all zero) + */ + ZT_INLINE void zero() noexcept + { + memoryZero(this); + } - /** - * @return Identity type (undefined if identity is null or invalid) - */ - ZT_INLINE Type type() const noexcept - { return m_type; } + /** + * @return Identity type (undefined if identity is null or invalid) + */ + ZT_INLINE Type type() const noexcept + { + return m_type; + } - /** - * Generate a new identity (address, key pair) - * - * This is a time consuming operation taking up to 5-10 seconds on some slower systems. - * - * @param t Type of identity to generate - * @return False if there was an error such as type being an invalid value - */ - bool generate(Type t); + /** + * Generate a new identity (address, key pair) + * + * This is a time consuming operation taking up to 5-10 seconds on some slower systems. + * + * @param t Type of identity to generate + * @return False if there was an error such as type being an invalid value + */ + bool generate(Type t); - /** - * Check the validity of this identity's address - * - * For type 0 identities this is slightly time consuming. For type 1 identities it's - * instantaneous. It should be done when a new identity is accepted for the very first - * time. - * - * @return True if validation check passes - */ - bool locallyValidate() const noexcept; + /** + * Check the validity of this identity's address + * + * For type 0 identities this is slightly time consuming. For type 1 identities it's + * instantaneous. It should be done when a new identity is accepted for the very first + * time. + * + * @return True if validation check passes + */ + bool locallyValidate() const noexcept; - /** - * @return True if this identity contains a private key - */ - ZT_INLINE bool hasPrivate() const noexcept - { return m_hasPrivate; } + /** + * @return True if this identity contains a private key + */ + ZT_INLINE bool hasPrivate() const noexcept + { + return m_hasPrivate; + } - /** - * @return This identity's address - */ - ZT_INLINE Address address() const noexcept - { return Address(m_fp.address); } + /** + * @return This identity's address + */ + ZT_INLINE Address address() const noexcept + { + return Address(m_fp.address); + } - /** - * @return Full fingerprint of this identity (address plus SHA384 of keys) - */ - ZT_INLINE const Fingerprint &fingerprint() const noexcept - { return m_fp; } + /** + * @return Full fingerprint of this identity (address plus SHA384 of keys) + */ + ZT_INLINE const Fingerprint& fingerprint() const noexcept + { + return m_fp; + } - /** - * Compute a hash of this identity's public and private keys. - * - * If there is no private key or the identity is NIL the buffer is filled with zero. - * - * @param h Buffer to store SHA384 hash - */ - void hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const; + /** + * Compute a hash of this identity's public and private keys. + * + * If there is no private key or the identity is NIL the buffer is filled with zero. + * + * @param h Buffer to store SHA384 hash + */ + void hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const; - /** - * Sign a message with this identity (private key required) - * - * The signature buffer should be large enough for the largest - * signature, which is currently 96 bytes. - * - * @param data Data to sign - * @param len Length of data - * @param sig Buffer to receive signature - * @param siglen Length of buffer - * @return Number of bytes actually written to sig or 0 on error - */ - unsigned int sign(const void *data, unsigned int len, void *sig, unsigned int siglen) const; + /** + * Sign a message with this identity (private key required) + * + * The signature buffer should be large enough for the largest + * signature, which is currently 96 bytes. + * + * @param data Data to sign + * @param len Length of data + * @param sig Buffer to receive signature + * @param siglen Length of buffer + * @return Number of bytes actually written to sig or 0 on error + */ + unsigned int sign(const void* data, unsigned int len, void* sig, unsigned int siglen) const; - /** - * Verify a message signature against this identity - * - * @param data Data to check - * @param len Length of data - * @param signature Signature bytes - * @param siglen Length of signature in bytes - * @return True if signature validates and data integrity checks - */ - bool verify(const void *data, unsigned int len, const void *sig, unsigned int siglen) const; + /** + * Verify a message signature against this identity + * + * @param data Data to check + * @param len Length of data + * @param signature Signature bytes + * @param siglen Length of signature in bytes + * @return True if signature validates and data integrity checks + */ + bool verify(const void* data, unsigned int len, const void* sig, unsigned int siglen) const; - /** - * Shortcut method to perform key agreement with another identity - * - * This identity must have a private key. (Check hasPrivate()) - * - * @param id Identity to agree with - * @param key Result parameter to fill with key bytes - * @return Was agreement successful? - */ - bool agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const; + /** + * Shortcut method to perform key agreement with another identity + * + * This identity must have a private key. (Check hasPrivate()) + * + * @param id Identity to agree with + * @param key Result parameter to fill with key bytes + * @return Was agreement successful? + */ + bool agree(const Identity& id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const; - /** - * Serialize to a more human-friendly string - * - * @param includePrivate If true, include private key (if it exists) - * @param buf Buffer to store string - * @return ASCII string representation of identity (pointer to buf) - */ - char *toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; + /** + * Serialize to a more human-friendly string + * + * @param includePrivate If true, include private key (if it exists) + * @param buf Buffer to store string + * @return ASCII string representation of identity (pointer to buf) + */ + char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; - ZT_INLINE String toString(const bool includePrivate = false) const - { - char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - toString(includePrivate, buf); - return String(buf); - } + ZT_INLINE String toString(const bool includePrivate = false) const + { + char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + toString(includePrivate, buf); + return String(buf); + } - /** - * Deserialize a human-friendly string - * - * Note: validation is for the format only. The locallyValidate() method - * must be used to check signature and address/key correspondence. - * - * @param str String to deserialize - * @return True if deserialization appears successful - */ - bool fromString(const char *str); + /** + * Deserialize a human-friendly string + * + * Note: validation is for the format only. The locallyValidate() method + * must be used to check signature and address/key correspondence. + * + * @param str String to deserialize + * @return True if deserialization appears successful + */ + bool fromString(const char* str); - /** - * Erase any private key in this identity object - */ - ZT_INLINE void erasePrivateKey() noexcept - { - Utils::burn(m_priv, sizeof(m_priv)); - m_hasPrivate = false; - } + /** + * Erase any private key in this identity object + */ + ZT_INLINE void erasePrivateKey() noexcept + { + Utils::burn(m_priv, sizeof(m_priv)); + m_hasPrivate = false; + } - /** - * @return True if this identity contains something - */ - explicit ZT_INLINE operator bool() const noexcept - { return (m_fp); } + /** + * @return True if this identity contains something + */ + explicit ZT_INLINE operator bool() const noexcept + { + return (m_fp); + } - ZT_INLINE unsigned long hashCode() const noexcept - { return m_fp.hashCode(); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return m_fp.hashCode(); + } - ZT_INLINE bool operator==(const Identity &id) const noexcept - { return (m_fp == id.m_fp); } + ZT_INLINE bool operator==(const Identity& id) const noexcept + { + return (m_fp == id.m_fp); + } - ZT_INLINE bool operator!=(const Identity &id) const noexcept - { return !(*this == id); } + ZT_INLINE bool operator!=(const Identity& id) const noexcept + { + return ! (*this == id); + } - ZT_INLINE bool operator<(const Identity &id) const noexcept - { return (m_fp < id.m_fp); } + ZT_INLINE bool operator<(const Identity& id) const noexcept + { + return (m_fp < id.m_fp); + } - ZT_INLINE bool operator>(const Identity &id) const noexcept - { return (id < *this); } + ZT_INLINE bool operator>(const Identity& id) const noexcept + { + return (id < *this); + } - ZT_INLINE bool operator<=(const Identity &id) const noexcept - { return !(id < *this); } + ZT_INLINE bool operator<=(const Identity& id) const noexcept + { + return ! (id < *this); + } - ZT_INLINE bool operator>=(const Identity &id) const noexcept - { return !(*this < id); } + ZT_INLINE bool operator>=(const Identity& id) const noexcept + { + return ! (*this < id); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_IDENTITY_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_IDENTITY_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; -private: - void m_computeHash(); + private: + void m_computeHash(); - Fingerprint m_fp; - uint8_t m_priv[ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE]; - uint8_t m_pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; - Type m_type; // _type determines which fields in _priv and _pub are used - bool m_hasPrivate; + Fingerprint m_fp; + uint8_t m_priv[ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE]; + uint8_t m_pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; + Type m_type; // _type determines which fields in _priv and _pub are used + bool m_hasPrivate; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/InetAddress.cpp b/core/InetAddress.cpp index f8c831531..18f1f985e 100644 --- a/core/InetAddress.cpp +++ b/core/InetAddress.cpp @@ -13,454 +13,481 @@ #define _WIN32_WINNT 0x06010000 -#include "Constants.hpp" #include "InetAddress.hpp" + +#include "Constants.hpp" #include "Utils.hpp" namespace ZeroTier { -static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(sockaddr_storage), "ZT_SOCKADDR_STORAGE_SIZE is incorrect on this platform, must be size of sockaddr_storage"); -static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal InetAddress, which should equal size of sockaddr_storage"); -static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(ZT_InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal ZT_InetAddress, which should equal size of sockaddr_storage"); +static_assert( + ZT_SOCKADDR_STORAGE_SIZE == sizeof(sockaddr_storage), + "ZT_SOCKADDR_STORAGE_SIZE is incorrect on this platform, must be size of sockaddr_storage"); +static_assert( + ZT_SOCKADDR_STORAGE_SIZE == sizeof(InetAddress), + "ZT_SOCKADDR_STORAGE_SIZE should equal InetAddress, which should equal size of sockaddr_storage"); +static_assert( + ZT_SOCKADDR_STORAGE_SIZE == sizeof(ZT_InetAddress), + "ZT_SOCKADDR_STORAGE_SIZE should equal ZT_InetAddress, which should equal size of sockaddr_storage"); -const InetAddress InetAddress::LO4((const void *) ("\x7f\x00\x00\x01"), 4, 0); -const InetAddress InetAddress::LO6((const void *) ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0); +const InetAddress InetAddress::LO4((const void*)("\x7f\x00\x00\x01"), 4, 0); +const InetAddress + InetAddress::LO6((const void*)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0); const InetAddress InetAddress::NIL; InetAddress::IpScope InetAddress::ipScope() const noexcept { - switch (as.ss.ss_family) { + switch (as.ss.ss_family) { + case AF_INET: { + const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr); + switch (ip >> 24U) { + case 0x00: + return ZT_IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) + case 0x06: + return ZT_IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) + case 0x0a: + return ZT_IP_SCOPE_PRIVATE; // 10.0.0.0/8 + case 0x15: // return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) + case 0x16: // return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) + case 0x19: // return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of + // Defense) + case 0x1a: // return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) + case 0x1c: // return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) + case 0x1d: // return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) + case 0x1e: // return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) + case 0x33: // return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of + // Social Security) + case 0x37: // return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) + case 0x38: // 56.0.0.0/8 (US Postal Service) + return ZT_IP_SCOPE_PSEUDOPRIVATE; + case 0x64: + if ((ip & 0xffc00000) == 0x64400000) + return ZT_IP_SCOPE_PRIVATE; // 100.64.0.0/10 + break; + case 0x7f: + return ZT_IP_SCOPE_LOOPBACK; // 127.0.0.0/8 + case 0xa9: + if ((ip & 0xffff0000) == 0xa9fe0000) + return ZT_IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 + break; + case 0xac: + if ((ip & 0xfff00000) == 0xac100000) + return ZT_IP_SCOPE_PRIVATE; // 172.16.0.0/12 + break; + case 0xc0: + if ((ip & 0xffff0000) == 0xc0a80000) + return ZT_IP_SCOPE_PRIVATE; // 192.168.0.0/16 + if ((ip & 0xffffff00) == 0xc0000200) + return ZT_IP_SCOPE_PRIVATE; // 192.0.2.0/24 + break; + case 0xc6: + if ((ip & 0xfffe0000) == 0xc6120000) + return ZT_IP_SCOPE_PRIVATE; // 198.18.0.0/15 + if ((ip & 0xffffff00) == 0xc6336400) + return ZT_IP_SCOPE_PRIVATE; // 198.51.100.0/24 + break; + case 0xcb: + if ((ip & 0xffffff00) == 0xcb007100) + return ZT_IP_SCOPE_PRIVATE; // 203.0.113.0/24 + break; + case 0xff: + return ZT_IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) + } + switch (ip >> 28U) { + case 0xe: + return ZT_IP_SCOPE_MULTICAST; // 224.0.0.0/4 + case 0xf: + return ZT_IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) + } + return ZT_IP_SCOPE_GLOBAL; + } - case AF_INET: { - const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr); - switch (ip >> 24U) { - case 0x00: - return ZT_IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) - case 0x06: - return ZT_IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) - case 0x0a: - return ZT_IP_SCOPE_PRIVATE; // 10.0.0.0/8 - case 0x15: //return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) - case 0x16: //return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) - case 0x19: //return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense) - case 0x1a: //return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) - case 0x1c: //return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) - case 0x1d: //return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) - case 0x1e: //return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) - case 0x33: //return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) - case 0x37: //return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) - case 0x38: // 56.0.0.0/8 (US Postal Service) - return ZT_IP_SCOPE_PSEUDOPRIVATE; - case 0x64: - if ((ip & 0xffc00000) == 0x64400000) return ZT_IP_SCOPE_PRIVATE; // 100.64.0.0/10 - break; - case 0x7f: - return ZT_IP_SCOPE_LOOPBACK; // 127.0.0.0/8 - case 0xa9: - if ((ip & 0xffff0000) == 0xa9fe0000) return ZT_IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 - break; - case 0xac: - if ((ip & 0xfff00000) == 0xac100000) return ZT_IP_SCOPE_PRIVATE; // 172.16.0.0/12 - break; - case 0xc0: - if ((ip & 0xffff0000) == 0xc0a80000) return ZT_IP_SCOPE_PRIVATE; // 192.168.0.0/16 - if ((ip & 0xffffff00) == 0xc0000200) return ZT_IP_SCOPE_PRIVATE; // 192.0.2.0/24 - break; - case 0xc6: - if ((ip & 0xfffe0000) == 0xc6120000) return ZT_IP_SCOPE_PRIVATE; // 198.18.0.0/15 - if ((ip & 0xffffff00) == 0xc6336400) return ZT_IP_SCOPE_PRIVATE; // 198.51.100.0/24 - break; - case 0xcb: - if ((ip & 0xffffff00) == 0xcb007100) return ZT_IP_SCOPE_PRIVATE; // 203.0.113.0/24 - break; - case 0xff: - return ZT_IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) - } - switch (ip >> 28U) { - case 0xe: - return ZT_IP_SCOPE_MULTICAST; // 224.0.0.0/4 - case 0xf: - return ZT_IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) - } - return ZT_IP_SCOPE_GLOBAL; - } - - case AF_INET6: { - const uint8_t *const ip = as.sa_in6.sin6_addr.s6_addr; - if ((ip[0] & 0xf0U) == 0xf0) { - if (ip[0] == 0xff) return ZT_IP_SCOPE_MULTICAST; // ff00::/8 - if ((ip[0] == 0xfe) && ((ip[1] & 0xc0U) == 0x80)) { - unsigned int k = 2; - while ((!ip[k]) && (k < 15)) ++k; - if ((k == 15) && (ip[15] == 0x01)) - return ZT_IP_SCOPE_LOOPBACK; // fe80::1/128 - else return ZT_IP_SCOPE_LINK_LOCAL; // fe80::/10 - } - if ((ip[0] & 0xfeU) == 0xfc) return ZT_IP_SCOPE_PRIVATE; // fc00::/7 - } - unsigned int k = 0; - while ((!ip[k]) && (k < 15)) ++k; - if (k == 15) { // all 0's except last byte - if (ip[15] == 0x01) return ZT_IP_SCOPE_LOOPBACK; // ::1/128 - if (ip[15] == 0x00) return ZT_IP_SCOPE_NONE; // ::/128 - } - return ZT_IP_SCOPE_GLOBAL; - } - - } - return ZT_IP_SCOPE_NONE; + case AF_INET6: { + const uint8_t* const ip = as.sa_in6.sin6_addr.s6_addr; + if ((ip[0] & 0xf0U) == 0xf0) { + if (ip[0] == 0xff) + return ZT_IP_SCOPE_MULTICAST; // ff00::/8 + if ((ip[0] == 0xfe) && ((ip[1] & 0xc0U) == 0x80)) { + unsigned int k = 2; + while ((! ip[k]) && (k < 15)) + ++k; + if ((k == 15) && (ip[15] == 0x01)) + return ZT_IP_SCOPE_LOOPBACK; // fe80::1/128 + else + return ZT_IP_SCOPE_LINK_LOCAL; // fe80::/10 + } + if ((ip[0] & 0xfeU) == 0xfc) + return ZT_IP_SCOPE_PRIVATE; // fc00::/7 + } + unsigned int k = 0; + while ((! ip[k]) && (k < 15)) + ++k; + if (k == 15) { // all 0's except last byte + if (ip[15] == 0x01) + return ZT_IP_SCOPE_LOOPBACK; // ::1/128 + if (ip[15] == 0x00) + return ZT_IP_SCOPE_NONE; // ::/128 + } + return ZT_IP_SCOPE_GLOBAL; + } + } + return ZT_IP_SCOPE_NONE; } -void InetAddress::set(const void *ipBytes, unsigned int ipLen, unsigned int port) noexcept +void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port) noexcept { - memoryZero(this); - if (ipLen == 4) { - as.sa_in.sin_family = AF_INET; - as.sa_in.sin_port = Utils::hton((uint16_t) port); - as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian< uint32_t >(ipBytes); - } else if (ipLen == 16) { - as.sa_in6.sin6_family = AF_INET6; - as.sa_in6.sin6_port = Utils::hton((uint16_t) port); - Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, ipBytes); - } + memoryZero(this); + if (ipLen == 4) { + as.sa_in.sin_family = AF_INET; + as.sa_in.sin_port = Utils::hton((uint16_t)port); + as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian(ipBytes); + } + else if (ipLen == 16) { + as.sa_in6.sin6_family = AF_INET6; + as.sa_in6.sin6_port = Utils::hton((uint16_t)port); + Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, ipBytes); + } } bool InetAddress::isDefaultRoute() const noexcept { - switch (as.ss.ss_family) { - case AF_INET: - return ((as.sa_in.sin_port == 0) && (as.sa_in.sin_addr.s_addr == 0)); - case AF_INET6: - if (as.sa_in6.sin6_port == 0) { - for (unsigned int i = 0;i < 16;++i) { - if (as.sa_in6.sin6_addr.s6_addr[i]) - return false; - } - return true; - } - return false; - default: - return false; - } + switch (as.ss.ss_family) { + case AF_INET: + return ((as.sa_in.sin_port == 0) && (as.sa_in.sin_addr.s_addr == 0)); + case AF_INET6: + if (as.sa_in6.sin6_port == 0) { + for (unsigned int i = 0; i < 16; ++i) { + if (as.sa_in6.sin6_addr.s6_addr[i]) + return false; + } + return true; + } + return false; + default: + return false; + } } -char *InetAddress::toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept +char* InetAddress::toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept { - char *p = toIpString(buf); - if (*p) { - while (*p) ++p; - *(p++) = '/'; - Utils::decimal(port(), p); - } - return buf; + char* p = toIpString(buf); + if (*p) { + while (*p) + ++p; + *(p++) = '/'; + Utils::decimal(port(), p); + } + return buf; } -char *InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept +char* InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept { - buf[0] = (char) 0; - switch (as.ss.ss_family) { - case AF_INET: - inet_ntop(AF_INET, &as.sa_in.sin_addr.s_addr, buf, INET_ADDRSTRLEN); - break; - case AF_INET6: - inet_ntop(AF_INET6, as.sa_in6.sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); - break; - } - return buf; + buf[0] = (char)0; + switch (as.ss.ss_family) { + case AF_INET: + inet_ntop(AF_INET, &as.sa_in.sin_addr.s_addr, buf, INET_ADDRSTRLEN); + break; + case AF_INET6: + inet_ntop(AF_INET6, as.sa_in6.sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); + break; + } + return buf; } -bool InetAddress::fromString(const char *ipSlashPort) noexcept +bool InetAddress::fromString(const char* ipSlashPort) noexcept { - char buf[64]; + char buf[64]; - memoryZero(this); + memoryZero(this); - if (!*ipSlashPort) - return true; - if (!Utils::scopy(buf, sizeof(buf), ipSlashPort)) - return false; + if (! *ipSlashPort) + return true; + if (! Utils::scopy(buf, sizeof(buf), ipSlashPort)) + return false; - char *portAt = buf; - while ((*portAt) && (*portAt != '/')) - ++portAt; - unsigned int port = 0; - if (*portAt) { - *(portAt++) = (char) 0; - port = Utils::strToUInt(portAt) & 0xffffU; - } + char* portAt = buf; + while ((*portAt) && (*portAt != '/')) + ++portAt; + unsigned int port = 0; + if (*portAt) { + *(portAt++) = (char)0; + port = Utils::strToUInt(portAt) & 0xffffU; + } - if (strchr(buf, ':')) { - as.sa_in6.sin6_family = AF_INET6; - as.sa_in6.sin6_port = Utils::hton((uint16_t) port); - inet_pton(AF_INET6, buf, as.sa_in6.sin6_addr.s6_addr); - return true; - } else if (strchr(buf, '.')) { - as.sa_in.sin_family = AF_INET; - as.sa_in.sin_port = Utils::hton((uint16_t) port); - inet_pton(AF_INET, buf, &as.sa_in.sin_addr.s_addr); - return true; - } + if (strchr(buf, ':')) { + as.sa_in6.sin6_family = AF_INET6; + as.sa_in6.sin6_port = Utils::hton((uint16_t)port); + inet_pton(AF_INET6, buf, as.sa_in6.sin6_addr.s6_addr); + return true; + } + else if (strchr(buf, '.')) { + as.sa_in.sin_family = AF_INET; + as.sa_in.sin_port = Utils::hton((uint16_t)port); + inet_pton(AF_INET, buf, &as.sa_in.sin_addr.s_addr); + return true; + } - return false; + return false; } InetAddress InetAddress::netmask() const noexcept { - InetAddress r(*this); - switch (r.as.ss.ss_family) { - case AF_INET: - r.as.sa_in.sin_addr.s_addr = Utils::hton((uint32_t) (0xffffffffU << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - if (bits) { - nm[0] = Utils::hton((uint64_t) ((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] = Utils::hton((uint64_t) ((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - } else { - nm[0] = 0; - nm[1] = 0; - } - Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); - } - break; - } - return r; + InetAddress r(*this); + switch (r.as.ss.ss_family) { + case AF_INET: + r.as.sa_in.sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits()))); + break; + case AF_INET6: { + uint64_t nm[2]; + const unsigned int bits = netmaskBits(); + if (bits) { + nm[0] = Utils::hton( + (uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); + nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); + } + else { + nm[0] = 0; + nm[1] = 0; + } + Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); + } break; + } + return r; } InetAddress InetAddress::broadcast() const noexcept { - if (as.ss.ss_family == AF_INET) { - InetAddress r(*this); - reinterpret_cast(&r)->sin_addr.s_addr |= Utils::hton((uint32_t) (0xffffffffU >> netmaskBits())); - return r; - } - return InetAddress(); + if (as.ss.ss_family == AF_INET) { + InetAddress r(*this); + reinterpret_cast(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits())); + return r; + } + return InetAddress(); } InetAddress InetAddress::network() const noexcept { - InetAddress r(*this); - switch (r.as.ss.ss_family) { - case AF_INET: - r.as.sa_in.sin_addr.s_addr &= Utils::hton((uint32_t) (0xffffffffU << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - Utils::copy<16>(nm, reinterpret_cast(&r)->sin6_addr.s6_addr); - nm[0] &= Utils::hton((uint64_t) ((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] &= Utils::hton((uint64_t) ((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); - } - break; - } - return r; + InetAddress r(*this); + switch (r.as.ss.ss_family) { + case AF_INET: + r.as.sa_in.sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits()))); + break; + case AF_INET6: { + uint64_t nm[2]; + const unsigned int bits = netmaskBits(); + Utils::copy<16>(nm, reinterpret_cast(&r)->sin6_addr.s6_addr); + nm[0] &= + Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); + nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); + Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); + } break; + } + return r; } -bool InetAddress::isEqualPrefix(const InetAddress &addr) const noexcept +bool InetAddress::isEqualPrefix(const InetAddress& addr) const noexcept { - if (addr.as.ss.ss_family == as.ss.ss_family) { - switch (as.ss.ss_family) { - case AF_INET6: { - const InetAddress mask(netmask()); - InetAddress addr_mask(addr.netmask()); - const uint8_t *const n = addr_mask.as.sa_in6.sin6_addr.s6_addr; - const uint8_t *const m = mask.as.sa_in6.sin6_addr.s6_addr; - const uint8_t *const a = addr.as.sa_in6.sin6_addr.s6_addr; - const uint8_t *const b = as.sa_in6.sin6_addr.s6_addr; - for (unsigned int i = 0;i < 16;++i) { - if ((a[i] & m[i]) != (b[i] & n[i])) - return false; - } - return true; - } - } - } - return false; + if (addr.as.ss.ss_family == as.ss.ss_family) { + switch (as.ss.ss_family) { + case AF_INET6: { + const InetAddress mask(netmask()); + InetAddress addr_mask(addr.netmask()); + const uint8_t* const n = addr_mask.as.sa_in6.sin6_addr.s6_addr; + const uint8_t* const m = mask.as.sa_in6.sin6_addr.s6_addr; + const uint8_t* const a = addr.as.sa_in6.sin6_addr.s6_addr; + const uint8_t* const b = as.sa_in6.sin6_addr.s6_addr; + for (unsigned int i = 0; i < 16; ++i) { + if ((a[i] & m[i]) != (b[i] & n[i])) + return false; + } + return true; + } + } + } + return false; } -bool InetAddress::containsAddress(const InetAddress &addr) const noexcept +bool InetAddress::containsAddress(const InetAddress& addr) const noexcept { - if (addr.as.ss.ss_family == as.ss.ss_family) { - switch (as.ss.ss_family) { - case AF_INET: { - const unsigned int bits = netmaskBits(); - if (bits == 0) - return true; - return ( - (Utils::ntoh((uint32_t) addr.as.sa_in.sin_addr.s_addr) >> (32 - bits)) == - (Utils::ntoh((uint32_t) as.sa_in.sin_addr.s_addr) >> (32 - bits)) - ); - } - case AF_INET6: { - const InetAddress mask(netmask()); - const uint8_t *const m = mask.as.sa_in6.sin6_addr.s6_addr; - const uint8_t *const a = addr.as.sa_in6.sin6_addr.s6_addr; - const uint8_t *const b = as.sa_in6.sin6_addr.s6_addr; - for (unsigned int i = 0;i < 16;++i) { - if ((a[i] & m[i]) != b[i]) - return false; - } - return true; - } - } - } - return false; + if (addr.as.ss.ss_family == as.ss.ss_family) { + switch (as.ss.ss_family) { + case AF_INET: { + const unsigned int bits = netmaskBits(); + if (bits == 0) + return true; + return ( + (Utils::ntoh((uint32_t)addr.as.sa_in.sin_addr.s_addr) >> (32 - bits)) + == (Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr) >> (32 - bits))); + } + case AF_INET6: { + const InetAddress mask(netmask()); + const uint8_t* const m = mask.as.sa_in6.sin6_addr.s6_addr; + const uint8_t* const a = addr.as.sa_in6.sin6_addr.s6_addr; + const uint8_t* const b = as.sa_in6.sin6_addr.s6_addr; + for (unsigned int i = 0; i < 16; ++i) { + if ((a[i] & m[i]) != b[i]) + return false; + } + return true; + } + } + } + return false; } bool InetAddress::isNetwork() const noexcept { - switch (as.ss.ss_family) { - case AF_INET: { - unsigned int bits = netmaskBits(); - if (bits <= 0) - return false; - if (bits >= 32) - return false; - const uint32_t ip = Utils::ntoh((uint32_t) as.sa_in.sin_addr.s_addr); - return ((ip & (0xffffffffU >> bits)) == 0); - } - case AF_INET6: { - unsigned int bits = netmaskBits(); - if (bits <= 0) - return false; - if (bits >= 128) - return false; - const uint8_t *const ip = as.sa_in6.sin6_addr.s6_addr; - unsigned int p = bits / 8; - if ((ip[p++] & (0xffU >> (bits % 8))) != 0) - return false; - while (p < 16) { - if (ip[p++]) - return false; - } - return true; - } - } - return false; + switch (as.ss.ss_family) { + case AF_INET: { + unsigned int bits = netmaskBits(); + if (bits <= 0) + return false; + if (bits >= 32) + return false; + const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr); + return ((ip & (0xffffffffU >> bits)) == 0); + } + case AF_INET6: { + unsigned int bits = netmaskBits(); + if (bits <= 0) + return false; + if (bits >= 128) + return false; + const uint8_t* const ip = as.sa_in6.sin6_addr.s6_addr; + unsigned int p = bits / 8; + if ((ip[p++] & (0xffU >> (bits % 8))) != 0) + return false; + while (p < 16) { + if (ip[p++]) + return false; + } + return true; + } + } + return false; } int InetAddress::marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept { - unsigned int port; - switch (as.ss.ss_family) { - case AF_INET: - port = Utils::ntoh((uint16_t) reinterpret_cast(this)->sin_port); - data[0] = 4; - data[1] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[0]; - data[2] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[1]; - data[3] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[2]; - data[4] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[3]; - data[5] = (uint8_t) (port >> 8U); - data[6] = (uint8_t) port; - return 7; - case AF_INET6: - port = Utils::ntoh((uint16_t) as.sa_in6.sin6_port); - data[0] = 6; - Utils::copy<16>(data + 1, as.sa_in6.sin6_addr.s6_addr); - data[17] = (uint8_t) (port >> 8U); - data[18] = (uint8_t) port; - return 19; - default: - data[0] = 0; - return 1; - } + unsigned int port; + switch (as.ss.ss_family) { + case AF_INET: + port = Utils::ntoh((uint16_t) reinterpret_cast(this)->sin_port); + data[0] = 4; + data[1] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[0]; + data[2] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[1]; + data[3] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[2]; + data[4] = reinterpret_cast(&as.sa_in.sin_addr.s_addr)[3]; + data[5] = (uint8_t)(port >> 8U); + data[6] = (uint8_t)port; + return 7; + case AF_INET6: + port = Utils::ntoh((uint16_t)as.sa_in6.sin6_port); + data[0] = 6; + Utils::copy<16>(data + 1, as.sa_in6.sin6_addr.s6_addr); + data[17] = (uint8_t)(port >> 8U); + data[18] = (uint8_t)port; + return 19; + default: + data[0] = 0; + return 1; + } } -int InetAddress::unmarshal(const uint8_t *restrict data, const int len) noexcept +int InetAddress::unmarshal(const uint8_t* restrict data, const int len) noexcept { - memoryZero(this); - if (unlikely(len <= 0)) - return -1; - switch (data[0]) { - case 0: - return 1; - case 4: - if (unlikely(len < 7)) - return -1; - as.sa_in.sin_family = AF_INET; - as.sa_in.sin_port = Utils::loadMachineEndian< uint16_t >(data + 5); - as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian< uint32_t >(data + 1); - return 7; - case 6: - if (unlikely(len < 19)) - return -1; - as.sa_in6.sin6_family = AF_INET6; - as.sa_in6.sin6_port = Utils::loadMachineEndian< uint16_t >(data + 17); - Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, data + 1); - return 19; - default: - return -1; - } + memoryZero(this); + if (unlikely(len <= 0)) + return -1; + switch (data[0]) { + case 0: + return 1; + case 4: + if (unlikely(len < 7)) + return -1; + as.sa_in.sin_family = AF_INET; + as.sa_in.sin_port = Utils::loadMachineEndian(data + 5); + as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian(data + 1); + return 7; + case 6: + if (unlikely(len < 19)) + return -1; + as.sa_in6.sin6_family = AF_INET6; + as.sa_in6.sin6_port = Utils::loadMachineEndian(data + 17); + Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, data + 1); + return 19; + default: + return -1; + } } -InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) noexcept +InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac) noexcept { - InetAddress r; - r.as.sa_in6.sin6_family = AF_INET6; - r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(64); - r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfe; - r.as.sa_in6.sin6_addr.s6_addr[1] = 0x80; - r.as.sa_in6.sin6_addr.s6_addr[2] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[3] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[4] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[5] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[6] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[7] = 0x00; - r.as.sa_in6.sin6_addr.s6_addr[8] = mac[0] & 0xfdU; - r.as.sa_in6.sin6_addr.s6_addr[9] = mac[1]; - r.as.sa_in6.sin6_addr.s6_addr[10] = mac[2]; - r.as.sa_in6.sin6_addr.s6_addr[11] = 0xff; - r.as.sa_in6.sin6_addr.s6_addr[12] = 0xfe; - r.as.sa_in6.sin6_addr.s6_addr[13] = mac[3]; - r.as.sa_in6.sin6_addr.s6_addr[14] = mac[4]; - r.as.sa_in6.sin6_addr.s6_addr[15] = mac[5]; - return r; + InetAddress r; + r.as.sa_in6.sin6_family = AF_INET6; + r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(64); + r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfe; + r.as.sa_in6.sin6_addr.s6_addr[1] = 0x80; + r.as.sa_in6.sin6_addr.s6_addr[2] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[3] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[4] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[5] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[6] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[7] = 0x00; + r.as.sa_in6.sin6_addr.s6_addr[8] = mac[0] & 0xfdU; + r.as.sa_in6.sin6_addr.s6_addr[9] = mac[1]; + r.as.sa_in6.sin6_addr.s6_addr[10] = mac[2]; + r.as.sa_in6.sin6_addr.s6_addr[11] = 0xff; + r.as.sa_in6.sin6_addr.s6_addr[12] = 0xfe; + r.as.sa_in6.sin6_addr.s6_addr[13] = mac[3]; + r.as.sa_in6.sin6_addr.s6_addr[14] = mac[4]; + r.as.sa_in6.sin6_addr.s6_addr[15] = mac[5]; + return r; } InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress) noexcept { - InetAddress r; - r.as.sa_in6.sin6_family = AF_INET6; - r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(88); // /88 includes 0xfd + network ID, discriminating by device ID below that - r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfd; - r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t) (nwid >> 56U); - r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t) (nwid >> 48U); - r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t) (nwid >> 40U); - r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t) (nwid >> 32U); - r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t) (nwid >> 24U); - r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t) (nwid >> 16U); - r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t) (nwid >> 8U); - r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t) nwid; - r.as.sa_in6.sin6_addr.s6_addr[9] = 0x99; - r.as.sa_in6.sin6_addr.s6_addr[10] = 0x93; - r.as.sa_in6.sin6_addr.s6_addr[11] = (uint8_t) (zeroTierAddress >> 32U); - r.as.sa_in6.sin6_addr.s6_addr[12] = (uint8_t) (zeroTierAddress >> 24U); - r.as.sa_in6.sin6_addr.s6_addr[13] = (uint8_t) (zeroTierAddress >> 16U); - r.as.sa_in6.sin6_addr.s6_addr[14] = (uint8_t) (zeroTierAddress >> 8U); - r.as.sa_in6.sin6_addr.s6_addr[15] = (uint8_t) zeroTierAddress; - return r; + InetAddress r; + r.as.sa_in6.sin6_family = AF_INET6; + r.as.sa_in6.sin6_port = + ZT_CONST_TO_BE_UINT16(88); // /88 includes 0xfd + network ID, discriminating by device ID below that + r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfd; + r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U); + r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48U); + r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40U); + r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32U); + r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24U); + r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16U); + r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8U); + r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t)nwid; + r.as.sa_in6.sin6_addr.s6_addr[9] = 0x99; + r.as.sa_in6.sin6_addr.s6_addr[10] = 0x93; + r.as.sa_in6.sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32U); + r.as.sa_in6.sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24U); + r.as.sa_in6.sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16U); + r.as.sa_in6.sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8U); + r.as.sa_in6.sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress; + return r; } InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress) noexcept { - nwid ^= (nwid >> 32U); - InetAddress r; - r.as.sa_in6.sin6_family = AF_INET6; - r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(40); - r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfc; - r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t) (nwid >> 24U); - r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t) (nwid >> 16U); - r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t) (nwid >> 8U); - r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t) nwid; - r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t) (zeroTierAddress >> 32U); - r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t) (zeroTierAddress >> 24U); - r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t) (zeroTierAddress >> 16U); - r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t) (zeroTierAddress >> 8U); - r.as.sa_in6.sin6_addr.s6_addr[9] = (uint8_t) zeroTierAddress; - r.as.sa_in6.sin6_addr.s6_addr[15] = 0x01; - return r; + nwid ^= (nwid >> 32U); + InetAddress r; + r.as.sa_in6.sin6_family = AF_INET6; + r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(40); + r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfc; + r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U); + r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16U); + r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8U); + r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t)nwid; + r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32U); + r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24U); + r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16U); + r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8U); + r.as.sa_in6.sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress; + r.as.sa_in6.sin6_addr.s6_addr[15] = 0x01; + return r; } extern "C" { @@ -468,4 +495,4 @@ extern const int ZT_AF_INET = (int)AF_INET; extern const int ZT_AF_INET6 = (int)AF_INET6; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/InetAddress.hpp b/core/InetAddress.hpp index bd2d20f9f..a2a669728 100644 --- a/core/InetAddress.hpp +++ b/core/InetAddress.hpp @@ -15,15 +15,15 @@ #define ZT_INETADDRESS_HPP #include "Constants.hpp" -#include "Utils.hpp" -#include "MAC.hpp" #include "Containers.hpp" +#include "MAC.hpp" #include "TriviallyCopyable.hpp" +#include "Utils.hpp" namespace ZeroTier { #define ZT_INETADDRESS_MARSHAL_SIZE_MAX 19 -#define ZT_INETADDRESS_STRING_SIZE_MAX 64 +#define ZT_INETADDRESS_STRING_SIZE_MAX 64 /** * C++ class that overlaps in size with sockaddr_storage and adds convenience methods @@ -33,594 +33,685 @@ namespace ZeroTier { * sockaddr_storage and used interchangeably. DO NOT change this by e.g. * adding non-static fields, since much code depends on this identity. */ -struct InetAddress : public TriviallyCopyable -{ -public: - /** - * Loopback IPv4 address (no port) - */ - static const InetAddress LO4; +struct InetAddress : public TriviallyCopyable { + public: + /** + * Loopback IPv4 address (no port) + */ + static const InetAddress LO4; - /** - * Loopback IPV6 address (no port) - */ - static const InetAddress LO6; + /** + * Loopback IPV6 address (no port) + */ + static const InetAddress LO6; - /** - * Null address - */ - static const InetAddress NIL; + /** + * Null address + */ + static const InetAddress NIL; - /** - * IP address scope - * - * Note that these values are in ascending order of path preference and - * MUST remain that way or Path must be changed to reflect. Also be sure - * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. - */ - typedef ZT_InetAddress_IpScope IpScope; + /** + * IP address scope + * + * Note that these values are in ascending order of path preference and + * MUST remain that way or Path must be changed to reflect. Also be sure + * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. + */ + typedef ZT_InetAddress_IpScope IpScope; - ZT_INLINE InetAddress() noexcept - { memoryZero(this); } + ZT_INLINE InetAddress() noexcept + { + memoryZero(this); + } - explicit ZT_INLINE InetAddress(const sockaddr_storage &ss) noexcept - { *this = ss; } + explicit ZT_INLINE InetAddress(const sockaddr_storage& ss) noexcept + { + *this = ss; + } - explicit ZT_INLINE InetAddress(const sockaddr_storage *const ss) noexcept - { *this = ss; } + explicit ZT_INLINE InetAddress(const sockaddr_storage* const ss) noexcept + { + *this = ss; + } - explicit ZT_INLINE InetAddress(const sockaddr &sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr& sa) noexcept + { + *this = sa; + } - explicit ZT_INLINE InetAddress(const sockaddr *const sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr* const sa) noexcept + { + *this = sa; + } - explicit ZT_INLINE InetAddress(const sockaddr_in &sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr_in& sa) noexcept + { + *this = sa; + } - explicit ZT_INLINE InetAddress(const sockaddr_in *const sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr_in* const sa) noexcept + { + *this = sa; + } - explicit ZT_INLINE InetAddress(const sockaddr_in6 &sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr_in6& sa) noexcept + { + *this = sa; + } - explicit ZT_INLINE InetAddress(const sockaddr_in6 *const sa) noexcept - { *this = sa; } + explicit ZT_INLINE InetAddress(const sockaddr_in6* const sa) noexcept + { + *this = sa; + } - ZT_INLINE InetAddress(const void *const ipBytes, const unsigned int ipLen, const unsigned int port) noexcept - { this->set(ipBytes, ipLen, port); } + ZT_INLINE InetAddress(const void* const ipBytes, const unsigned int ipLen, const unsigned int port) noexcept + { + this->set(ipBytes, ipLen, port); + } - ZT_INLINE InetAddress(const uint32_t ipv4, const unsigned int port) noexcept - { this->set(&ipv4, 4, port); } + ZT_INLINE InetAddress(const uint32_t ipv4, const unsigned int port) noexcept + { + this->set(&ipv4, 4, port); + } - explicit ZT_INLINE InetAddress(const char *const ipSlashPort) noexcept - { this->fromString(ipSlashPort); } + explicit ZT_INLINE InetAddress(const char* const ipSlashPort) noexcept + { + this->fromString(ipSlashPort); + } - ZT_INLINE InetAddress &operator=(const sockaddr_storage &ss) noexcept - { - as.ss = ss; - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_storage& ss) noexcept + { + as.ss = ss; + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr_storage *ss) noexcept - { - if (ss) - as.ss = *ss; - else memoryZero(this); - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_storage* ss) noexcept + { + if (ss) + as.ss = *ss; + else + memoryZero(this); + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr_in &sa) noexcept - { - memoryZero(this); - as.sa_in = sa; - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_in& sa) noexcept + { + memoryZero(this); + as.sa_in = sa; + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr_in *sa) noexcept - { - memoryZero(this); - if (sa) - as.sa_in = *sa; - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_in* sa) noexcept + { + memoryZero(this); + if (sa) + as.sa_in = *sa; + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr_in6 &sa) noexcept - { - memoryZero(this); - as.sa_in6 = sa; - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_in6& sa) noexcept + { + memoryZero(this); + as.sa_in6 = sa; + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr_in6 *sa) noexcept - { - memoryZero(this); - if (sa) - as.sa_in6 = *sa; - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr_in6* sa) noexcept + { + memoryZero(this); + if (sa) + as.sa_in6 = *sa; + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr &sa) noexcept - { - memoryZero(this); - if (sa.sa_family == AF_INET) - as.sa_in = *reinterpret_cast(&sa); - else if (sa.sa_family == AF_INET6) - as.sa_in6 = *reinterpret_cast(&sa); - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr& sa) noexcept + { + memoryZero(this); + if (sa.sa_family == AF_INET) + as.sa_in = *reinterpret_cast(&sa); + else if (sa.sa_family == AF_INET6) + as.sa_in6 = *reinterpret_cast(&sa); + return *this; + } - ZT_INLINE InetAddress &operator=(const sockaddr *sa) noexcept - { - memoryZero(this); - if (sa) { - if (sa->sa_family == AF_INET) - as.sa_in = *reinterpret_cast(sa); - else if (sa->sa_family == AF_INET6) - as.sa_in6 = *reinterpret_cast(sa); - } - return *this; - } + ZT_INLINE InetAddress& operator=(const sockaddr* sa) noexcept + { + memoryZero(this); + if (sa) { + if (sa->sa_family == AF_INET) + as.sa_in = *reinterpret_cast(sa); + else if (sa->sa_family == AF_INET6) + as.sa_in6 = *reinterpret_cast(sa); + } + return *this; + } - ZT_INLINE void clear() noexcept - { memoryZero(this); } + ZT_INLINE void clear() noexcept + { + memoryZero(this); + } - /** - * @return IP scope classification (e.g. loopback, link-local, private, global) - */ - IpScope ipScope() const noexcept; + /** + * @return IP scope classification (e.g. loopback, link-local, private, global) + */ + IpScope ipScope() const noexcept; - /** - * Set from a raw IP and port number - * - * @param ipBytes Bytes of IP address in network byte order - * @param ipLen Length of IP address: 4 or 16 - * @param port Port number or 0 for none - */ - void set(const void *ipBytes, unsigned int ipLen, unsigned int port) noexcept; + /** + * Set from a raw IP and port number + * + * @param ipBytes Bytes of IP address in network byte order + * @param ipLen Length of IP address: 4 or 16 + * @param port Port number or 0 for none + */ + void set(const void* ipBytes, unsigned int ipLen, unsigned int port) noexcept; - /** - * Set the port component - * - * @param port Port, 0 to 65535 - */ - ZT_INLINE void setPort(unsigned int port) noexcept - { - switch (as.ss.ss_family) { - case AF_INET: - as.sa_in.sin_port = Utils::hton((uint16_t)port); - break; - case AF_INET6: - as.sa_in6.sin6_port = Utils::hton((uint16_t)port); - break; - } - } + /** + * Set the port component + * + * @param port Port, 0 to 65535 + */ + ZT_INLINE void setPort(unsigned int port) noexcept + { + switch (as.ss.ss_family) { + case AF_INET: + as.sa_in.sin_port = Utils::hton((uint16_t)port); + break; + case AF_INET6: + as.sa_in6.sin6_port = Utils::hton((uint16_t)port); + break; + } + } - /** - * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0) - */ - bool isDefaultRoute() const noexcept; + /** + * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0) + */ + bool isDefaultRoute() const noexcept; - /** - * @return ASCII IP/port format representation - */ - char *toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; + /** + * @return ASCII IP/port format representation + */ + char* toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; - ZT_INLINE String toString() const - { - char buf[ZT_INETADDRESS_STRING_SIZE_MAX]; - toString(buf); - return String(buf); - } + ZT_INLINE String toString() const + { + char buf[ZT_INETADDRESS_STRING_SIZE_MAX]; + toString(buf); + return String(buf); + } - /** - * @return IP portion only, in ASCII string format - */ - char *toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; + /** + * @return IP portion only, in ASCII string format + */ + char* toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; - ZT_INLINE String toIpString() const - { - char buf[ZT_INETADDRESS_STRING_SIZE_MAX]; - toIpString(buf); - return String(buf); - } + ZT_INLINE String toIpString() const + { + char buf[ZT_INETADDRESS_STRING_SIZE_MAX]; + toIpString(buf); + return String(buf); + } - /** - * @param ipSlashPort IP/port (port is optional, will be 0 if not included) - * @return True if address appeared to be valid - */ - bool fromString(const char *ipSlashPort) noexcept; + /** + * @param ipSlashPort IP/port (port is optional, will be 0 if not included) + * @return True if address appeared to be valid + */ + bool fromString(const char* ipSlashPort) noexcept; - /** - * @return Port or 0 if no port component defined - */ - ZT_INLINE unsigned int port() const noexcept - { - switch (as.ss.ss_family) { - case AF_INET: - return Utils::ntoh((uint16_t)as.sa_in.sin_port); - case AF_INET6: - return Utils::ntoh((uint16_t)as.sa_in6.sin6_port); - default: - return 0; - } - } + /** + * @return Port or 0 if no port component defined + */ + ZT_INLINE unsigned int port() const noexcept + { + switch (as.ss.ss_family) { + case AF_INET: + return Utils::ntoh((uint16_t)as.sa_in.sin_port); + case AF_INET6: + return Utils::ntoh((uint16_t)as.sa_in6.sin6_port); + default: + return 0; + } + } - /** - * Alias for port() - * - * This just aliases port() to make code more readable when netmask bits - * are stuffed there, as they are in Network, EthernetTap, and a few other - * spots. - * - * @return Netmask bits - */ - ZT_INLINE unsigned int netmaskBits() const noexcept - { return port(); } + /** + * Alias for port() + * + * This just aliases port() to make code more readable when netmask bits + * are stuffed there, as they are in Network, EthernetTap, and a few other + * spots. + * + * @return Netmask bits + */ + ZT_INLINE unsigned int netmaskBits() const noexcept + { + return port(); + } - /** - * @return True if netmask bits is valid for the address type - */ - ZT_INLINE bool netmaskBitsValid() const noexcept - { - const unsigned int n = port(); - switch (as.ss.ss_family) { - case AF_INET: - return (n <= 32); - case AF_INET6: - return (n <= 128); - } - return false; - } + /** + * @return True if netmask bits is valid for the address type + */ + ZT_INLINE bool netmaskBitsValid() const noexcept + { + const unsigned int n = port(); + switch (as.ss.ss_family) { + case AF_INET: + return (n <= 32); + case AF_INET6: + return (n <= 128); + } + return false; + } - /** - * Alias for port() - * - * This just aliases port() because for gateways we use this field to - * store the gateway metric. - * - * @return Gateway metric - */ - ZT_INLINE unsigned int metric() const noexcept - { return port(); } + /** + * Alias for port() + * + * This just aliases port() because for gateways we use this field to + * store the gateway metric. + * + * @return Gateway metric + */ + ZT_INLINE unsigned int metric() const noexcept + { + return port(); + } - /** - * Construct a full netmask as an InetAddress - * - * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged) - */ - InetAddress netmask() const noexcept; + /** + * Construct a full netmask as an InetAddress + * + * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged) + */ + InetAddress netmask() const noexcept; - /** - * Constructs a broadcast address from a network/netmask address - * - * This is only valid for IPv4 and will return a NULL InetAddress for other - * address families. - * - * @return Broadcast address (only IP portion is meaningful) - */ - InetAddress broadcast() const noexcept; + /** + * Constructs a broadcast address from a network/netmask address + * + * This is only valid for IPv4 and will return a NULL InetAddress for other + * address families. + * + * @return Broadcast address (only IP portion is meaningful) + */ + InetAddress broadcast() const noexcept; - /** - * Return the network -- a.k.a. the IP ANDed with the netmask - * - * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24 - */ - InetAddress network() const noexcept; + /** + * Return the network -- a.k.a. the IP ANDed with the netmask + * + * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24 + */ + InetAddress network() const noexcept; - /** - * Test whether this IPv6 prefix matches the prefix of a given IPv6 address - * - * @param addr Address to check - * @return True if this IPv6 prefix matches the prefix of a given IPv6 address - */ - bool isEqualPrefix(const InetAddress &addr) const noexcept; + /** + * Test whether this IPv6 prefix matches the prefix of a given IPv6 address + * + * @param addr Address to check + * @return True if this IPv6 prefix matches the prefix of a given IPv6 address + */ + bool isEqualPrefix(const InetAddress& addr) const noexcept; - /** - * Test whether this IP/netmask contains this address - * - * @param addr Address to check - * @return True if this IP/netmask (route) contains this address - */ - bool containsAddress(const InetAddress &addr) const noexcept; + /** + * Test whether this IP/netmask contains this address + * + * @param addr Address to check + * @return True if this IP/netmask (route) contains this address + */ + bool containsAddress(const InetAddress& addr) const noexcept; - /** - * @return True if this is an IPv4 address - */ - ZT_INLINE bool isV4() const noexcept - { return (as.ss.ss_family == AF_INET); } + /** + * @return True if this is an IPv4 address + */ + ZT_INLINE bool isV4() const noexcept + { + return (as.ss.ss_family == AF_INET); + } - /** - * @return True if this is an IPv6 address - */ - ZT_INLINE bool isV6() const noexcept - { return (as.ss.ss_family == AF_INET6); } + /** + * @return True if this is an IPv6 address + */ + ZT_INLINE bool isV6() const noexcept + { + return (as.ss.ss_family == AF_INET6); + } - /** - * @return pointer to raw address bytes or NULL if not available - */ - ZT_INLINE const void *rawIpData() const noexcept - { - switch (as.ss.ss_family) { - case AF_INET: - return reinterpret_cast(&(as.sa_in.sin_addr.s_addr)); - case AF_INET6: - return reinterpret_cast(as.sa_in6.sin6_addr.s6_addr); - default: - return nullptr; - } - } + /** + * @return pointer to raw address bytes or NULL if not available + */ + ZT_INLINE const void* rawIpData() const noexcept + { + switch (as.ss.ss_family) { + case AF_INET: + return reinterpret_cast(&(as.sa_in.sin_addr.s_addr)); + case AF_INET6: + return reinterpret_cast(as.sa_in6.sin6_addr.s6_addr); + default: + return nullptr; + } + } - /** - * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6 - */ - ZT_INLINE InetAddress ipOnly() const noexcept - { - InetAddress r; - switch (as.ss.ss_family) { - case AF_INET: - r.as.sa_in.sin_family = AF_INET; - r.as.sa_in.sin_addr.s_addr = as.sa_in.sin_addr.s_addr; - break; - case AF_INET6: - r.as.sa_in6.sin6_family = AF_INET6; - Utils::copy< 16 >(r.as.sa_in6.sin6_addr.s6_addr, as.sa_in6.sin6_addr.s6_addr); - break; - } - return r; - } + /** + * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6 + */ + ZT_INLINE InetAddress ipOnly() const noexcept + { + InetAddress r; + switch (as.ss.ss_family) { + case AF_INET: + r.as.sa_in.sin_family = AF_INET; + r.as.sa_in.sin_addr.s_addr = as.sa_in.sin_addr.s_addr; + break; + case AF_INET6: + r.as.sa_in6.sin6_family = AF_INET6; + Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, as.sa_in6.sin6_addr.s6_addr); + break; + } + return r; + } - /** - * Performs an IP-only comparison or, if that is impossible, a memcmp() - * - * @param a InetAddress to compare again - * @return True if only IP portions are equal (false for non-IP or null addresses) - */ - ZT_INLINE bool ipsEqual(const InetAddress &a) const noexcept - { - const uint8_t f = as.ss.ss_family; - if (f == a.as.ss.ss_family) { - if (f == AF_INET) - return as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr; - if (f == AF_INET6) - return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0; - return memcmp(this, &a, sizeof(InetAddress)) == 0; - } - return false; - } + /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * + * @param a InetAddress to compare again + * @return True if only IP portions are equal (false for non-IP or null addresses) + */ + ZT_INLINE bool ipsEqual(const InetAddress& a) const noexcept + { + const uint8_t f = as.ss.ss_family; + if (f == a.as.ss.ss_family) { + if (f == AF_INET) + return as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr; + if (f == AF_INET6) + return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0; + return memcmp(this, &a, sizeof(InetAddress)) == 0; + } + return false; + } - /** - * Performs an IP-only comparison or, if that is impossible, a memcmp() - * - * This version compares only the first 64 bits of IPv6 addresses. - * - * @param a InetAddress to compare again - * @return True if only IP portions are equal (false for non-IP or null addresses) - */ - ZT_INLINE bool ipsEqual2(const InetAddress &a) const noexcept - { - const uint8_t f = as.ss.ss_family; - if (f == a.as.ss.ss_family) { - if (f == AF_INET) - return as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr; - if (f == AF_INET6) - return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 8) == 0; - return (memcmp(this, &a, sizeof(InetAddress)) == 0); - } - return false; - } + /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * + * This version compares only the first 64 bits of IPv6 addresses. + * + * @param a InetAddress to compare again + * @return True if only IP portions are equal (false for non-IP or null addresses) + */ + ZT_INLINE bool ipsEqual2(const InetAddress& a) const noexcept + { + const uint8_t f = as.ss.ss_family; + if (f == a.as.ss.ss_family) { + if (f == AF_INET) + return as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr; + if (f == AF_INET6) + return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 8) == 0; + return (memcmp(this, &a, sizeof(InetAddress)) == 0); + } + return false; + } - ZT_INLINE unsigned long hashCode() const noexcept - { - if (as.ss.ss_family == AF_INET) { - return (unsigned long)Utils::hash32(((uint32_t)as.sa_in.sin_addr.s_addr + (uint32_t)as.sa_in.sin_port) ^ (uint32_t)Utils::s_mapNonce); - } else if (as.ss.ss_family == AF_INET6) { - return (unsigned long)Utils::hash64( - (Utils::loadMachineEndian< uint64_t >(as.sa_in6.sin6_addr.s6_addr) + - Utils::loadMachineEndian< uint64_t >(as.sa_in6.sin6_addr.s6_addr + 8) + - (uint64_t)as.sa_in6.sin6_port) ^ - Utils::s_mapNonce); - } - return Utils::fnv1a32(this, sizeof(InetAddress)); - } + ZT_INLINE unsigned long hashCode() const noexcept + { + if (as.ss.ss_family == AF_INET) { + return (unsigned long)Utils::hash32( + ((uint32_t)as.sa_in.sin_addr.s_addr + (uint32_t)as.sa_in.sin_port) ^ (uint32_t)Utils::s_mapNonce); + } + else if (as.ss.ss_family == AF_INET6) { + return (unsigned long)Utils::hash64( + (Utils::loadMachineEndian(as.sa_in6.sin6_addr.s6_addr) + + Utils::loadMachineEndian(as.sa_in6.sin6_addr.s6_addr + 8) + (uint64_t)as.sa_in6.sin6_port) + ^ Utils::s_mapNonce); + } + return Utils::fnv1a32(this, sizeof(InetAddress)); + } - /** - * Check whether this is a network/route rather than an IP assignment - * - * A network is an IP/netmask where everything after the netmask is - * zero e.g. 10.0.0.0/8. - * - * @return True if everything after netmask bits is zero - */ - bool isNetwork() const noexcept; + /** + * Check whether this is a network/route rather than an IP assignment + * + * A network is an IP/netmask where everything after the netmask is + * zero e.g. 10.0.0.0/8. + * + * @return True if everything after netmask bits is zero + */ + bool isNetwork() const noexcept; - /** - * @return True if address family is non-zero - */ - explicit ZT_INLINE operator bool() const noexcept - { return (as.ss.ss_family != 0); } + /** + * @return True if address family is non-zero + */ + explicit ZT_INLINE operator bool() const noexcept + { + return (as.ss.ss_family != 0); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_INETADDRESS_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_INETADDRESS_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept; + int marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept; - int unmarshal(const uint8_t *restrict data, int len) noexcept; + int unmarshal(const uint8_t* restrict data, int len) noexcept; - ZT_INLINE bool operator==(const InetAddress &a) const noexcept - { - if (as.ss.ss_family == a.as.ss.ss_family) { - if (as.ss.ss_family == AF_INET) - return ((as.sa_in.sin_port == a.as.sa_in.sin_port) && (as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr)); - if (as.ss.ss_family == AF_INET6) - return ((as.sa_in6.sin6_port == a.as.sa_in6.sin6_port) && (memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0)); - return memcmp(this, &a, sizeof(InetAddress)) == 0; - } - return false; - } + ZT_INLINE bool operator==(const InetAddress& a) const noexcept + { + if (as.ss.ss_family == a.as.ss.ss_family) { + if (as.ss.ss_family == AF_INET) + return ( + (as.sa_in.sin_port == a.as.sa_in.sin_port) + && (as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr)); + if (as.ss.ss_family == AF_INET6) + return ( + (as.sa_in6.sin6_port == a.as.sa_in6.sin6_port) + && (memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0)); + return memcmp(this, &a, sizeof(InetAddress)) == 0; + } + return false; + } - ZT_INLINE bool operator<(const InetAddress &a) const noexcept - { - if (as.ss.ss_family == a.as.ss.ss_family) { - if (as.ss.ss_family == AF_INET) { - const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in.sin_port); - const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in.sin_port); - if (p0 == p1) - return Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr) < Utils::ntoh((uint32_t)a.as.sa_in.sin_addr.s_addr); - return p0 < p1; - } - if (as.ss.ss_family == AF_INET6) { - const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in6.sin6_port); - const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in6.sin6_port); - if (p0 == p1) - return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) < 0; - return p0 < p1; - } - return memcmp(this, &a, sizeof(InetAddress)) < 0; - } - return as.ss.ss_family < a.as.ss.ss_family; - } + ZT_INLINE bool operator<(const InetAddress& a) const noexcept + { + if (as.ss.ss_family == a.as.ss.ss_family) { + if (as.ss.ss_family == AF_INET) { + const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in.sin_port); + const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in.sin_port); + if (p0 == p1) + return Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr) + < Utils::ntoh((uint32_t)a.as.sa_in.sin_addr.s_addr); + return p0 < p1; + } + if (as.ss.ss_family == AF_INET6) { + const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in6.sin6_port); + const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in6.sin6_port); + if (p0 == p1) + return memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) < 0; + return p0 < p1; + } + return memcmp(this, &a, sizeof(InetAddress)) < 0; + } + return as.ss.ss_family < a.as.ss.ss_family; + } - ZT_INLINE bool operator!=(const InetAddress &a) const noexcept - { return !(*this == a); } + ZT_INLINE bool operator!=(const InetAddress& a) const noexcept + { + return ! (*this == a); + } - ZT_INLINE bool operator>(const InetAddress &a) const noexcept - { return (a < *this); } + ZT_INLINE bool operator>(const InetAddress& a) const noexcept + { + return (a < *this); + } - ZT_INLINE bool operator<=(const InetAddress &a) const noexcept - { return !(a < *this); } + ZT_INLINE bool operator<=(const InetAddress& a) const noexcept + { + return ! (a < *this); + } - ZT_INLINE bool operator>=(const InetAddress &a) const noexcept - { return !(*this < a); } + ZT_INLINE bool operator>=(const InetAddress& a) const noexcept + { + return ! (*this < a); + } - /** - * Compute an IPv6 link-local address - * - * @param mac MAC address seed - * @return IPv6 link-local address - */ - static InetAddress makeIpv6LinkLocal(const MAC &mac) noexcept; + /** + * Compute an IPv6 link-local address + * + * @param mac MAC address seed + * @return IPv6 link-local address + */ + static InetAddress makeIpv6LinkLocal(const MAC& mac) noexcept; - /** - * Compute private IPv6 unicast address from network ID and ZeroTier address - * - * This generates a private unicast IPv6 address that is mostly compliant - * with the letter of RFC4193 and certainly compliant in spirit. - * - * RFC4193 specifies a format of: - * - * | 7 bits |1| 40 bits | 16 bits | 64 bits | - * | Prefix |L| Global ID | Subnet ID | Interface ID | - * - * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then - * the network ID is filled into the global ID, subnet ID, and first byte - * of the "interface ID" field. Since the first 40 bits of the network ID - * is the unique ZeroTier address of its controller, this makes a very - * good random global ID. Since network IDs have 24 more bits, we let it - * overflow into the interface ID. - * - * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier - * port in hex. - * - * Finally we fill the remaining 40 bits of the interface ID field with - * the 40-bit unique ZeroTier device ID of the network member. - * - * This yields a valid RFC4193 address with a random global ID, a - * meaningful subnet ID, and a unique interface ID, all mappable back onto - * ZeroTier space. - * - * This in turn could allow us, on networks numbered this way, to emulate - * IPv6 NDP and eliminate all multicast. This could be beneficial for - * small devices and huge networks, e.g. IoT applications. - * - * The returned address is given an odd prefix length of /88, since within - * a given network only the last 40 bits (device ID) are variable. This - * is a bit unusual but as far as we know should not cause any problems with - * any non-braindead IPv6 stack. - * - * @param nwid 64-bit network ID - * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) - * @return IPv6 private unicast address with /88 netmask - */ - static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress) noexcept; + /** + * Compute private IPv6 unicast address from network ID and ZeroTier address + * + * This generates a private unicast IPv6 address that is mostly compliant + * with the letter of RFC4193 and certainly compliant in spirit. + * + * RFC4193 specifies a format of: + * + * | 7 bits |1| 40 bits | 16 bits | 64 bits | + * | Prefix |L| Global ID | Subnet ID | Interface ID | + * + * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then + * the network ID is filled into the global ID, subnet ID, and first byte + * of the "interface ID" field. Since the first 40 bits of the network ID + * is the unique ZeroTier address of its controller, this makes a very + * good random global ID. Since network IDs have 24 more bits, we let it + * overflow into the interface ID. + * + * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier + * port in hex. + * + * Finally we fill the remaining 40 bits of the interface ID field with + * the 40-bit unique ZeroTier device ID of the network member. + * + * This yields a valid RFC4193 address with a random global ID, a + * meaningful subnet ID, and a unique interface ID, all mappable back onto + * ZeroTier space. + * + * This in turn could allow us, on networks numbered this way, to emulate + * IPv6 NDP and eliminate all multicast. This could be beneficial for + * small devices and huge networks, e.g. IoT applications. + * + * The returned address is given an odd prefix length of /88, since within + * a given network only the last 40 bits (device ID) are variable. This + * is a bit unusual but as far as we know should not cause any problems with + * any non-braindead IPv6 stack. + * + * @param nwid 64-bit network ID + * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) + * @return IPv6 private unicast address with /88 netmask + */ + static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress) noexcept; - /** - * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address - */ - static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress) noexcept; + /** + * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address + */ + static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress) noexcept; - /** - * Union allowing this to be accessed as a sockaddr of any supported type. - */ - union - { - sockaddr_storage ss; - sockaddr sa; - sockaddr_in sa_in; - sockaddr_in6 sa_in6; - } as; + /** + * Union allowing this to be accessed as a sockaddr of any supported type. + */ + union { + sockaddr_storage ss; + sockaddr sa; + sockaddr_in sa_in; + sockaddr_in6 sa_in6; + } as; }; -static ZT_INLINE InetAddress *asInetAddress(sockaddr_in *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE InetAddress* asInetAddress(sockaddr_in* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE InetAddress *asInetAddress(sockaddr_in6 *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE InetAddress* asInetAddress(sockaddr_in6* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE InetAddress *asInetAddress(sockaddr *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE InetAddress* asInetAddress(sockaddr* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE InetAddress *asInetAddress(sockaddr_storage *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE InetAddress* asInetAddress(sockaddr_storage* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE InetAddress *asInetAddress(ZT_InetAddress *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE InetAddress* asInetAddress(ZT_InetAddress* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_in *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_in* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_in6 *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_in6* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE const InetAddress *asInetAddress(const sockaddr *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE const InetAddress* asInetAddress(const sockaddr* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_storage *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_storage* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE const InetAddress *asInetAddress(const ZT_InetAddress *const p) noexcept -{ return reinterpret_cast(p); } +static ZT_INLINE const InetAddress* asInetAddress(const ZT_InetAddress* const p) noexcept +{ + return reinterpret_cast(p); +} -static ZT_INLINE InetAddress &asInetAddress(sockaddr_in &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress& asInetAddress(sockaddr_in& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE InetAddress &asInetAddress(sockaddr_in6 &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress& asInetAddress(sockaddr_in6& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE InetAddress &asInetAddress(sockaddr &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress& asInetAddress(sockaddr& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE InetAddress &asInetAddress(sockaddr_storage &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress& asInetAddress(sockaddr_storage& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE InetAddress &asInetAddress(ZT_InetAddress &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress& asInetAddress(ZT_InetAddress& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_in &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_in& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_in6 &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_in6& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE const InetAddress &asInetAddress(const sockaddr &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress& asInetAddress(const sockaddr& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_storage &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_storage& p) noexcept +{ + return *reinterpret_cast(&p); +} -static ZT_INLINE const InetAddress &asInetAddress(const ZT_InetAddress &p) noexcept -{ return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress& asInetAddress(const ZT_InetAddress& p) noexcept +{ + return *reinterpret_cast(&p); +} -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/LZ4.cpp b/core/LZ4.cpp index 8d33f8646..90c7b376f 100644 --- a/core/LZ4.cpp +++ b/core/LZ4.cpp @@ -9,9 +9,9 @@ modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -29,25 +29,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ // Some modifications were made for ZeroTier but this code remains under the // original LZ4 license. #include "LZ4.hpp" + #include "Utils.hpp" -#include -#include #include +#include +#include #ifdef _MSC_VER #define FORCE_INLINE __forceinline #include -#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else #define FORCE_INLINE ZT_INLINE #endif @@ -61,44 +62,40 @@ namespace { // #define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ #define LZ4_MEMORY_USAGE 14 -typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ -FORCE_INLINE void LZ4_resetStream(LZ4_stream_t *streamPtr); +FORCE_INLINE void LZ4_resetStream(LZ4_stream_t* streamPtr); -#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) -#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ -typedef struct -{ - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t *dictionary; - uint8_t *bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; +typedef struct { + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; } LZ4_stream_t_internal; -typedef struct -{ - const uint8_t *externalDict; - size_t extDictSize; - const uint8_t *prefixEnd; - size_t prefixSize; +typedef struct { + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -union LZ4_stream_u -{ - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; -}; /* previously typedef'd to LZ4_stream_t */ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4) +union LZ4_stream_u { + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_stream_t */ -#define LZ4_STREAMDECODESIZE_U64 4 -union LZ4_streamDecode_u -{ - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; -}; /* previously typedef'd to LZ4_streamDecode_t */ +#define LZ4_STREAMDECODESIZE_U64 4 +union LZ4_streamDecode_u { + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_streamDecode_t */ #ifndef HEAPMODE #define HEAPMODE 0 @@ -114,8 +111,8 @@ union LZ4_streamDecode_u #define LZ4_FORCE_SW_BITCOUNT #endif -#define ALLOCATOR(n, s) calloc(n,s) -#define FREEMEM free +#define ALLOCATOR(n, s) calloc(n, s) +#define FREEMEM free typedef uint8_t BYTE; typedef uint16_t U16; @@ -132,727 +129,871 @@ typedef uintptr_t reg_t; #endif #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 2) -FORCE_INLINE U16 LZ4_read16(const void *memPtr) -{ return *(const U16 *)memPtr; } - -FORCE_INLINE U32 LZ4_read32(const void *memPtr) -{ return *(const U32 *)memPtr; } - -FORCE_INLINE reg_t LZ4_read_ARCH(const void *memPtr) -{ return *(const reg_t *)memPtr; } - -FORCE_INLINE void LZ4_write16(void *memPtr, U16 value) -{ *(U16 *)memPtr = value; } - -FORCE_INLINE void LZ4_write32(void *memPtr, U32 value) -{ *(U32 *)memPtr = value; } - -#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 1) -typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; -FORCE_INLINE U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } -FORCE_INLINE U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } -FORCE_INLINE reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } -FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } -FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } -#else /* safe and portable */ FORCE_INLINE U16 LZ4_read16(const void* memPtr) { - U16 val; Utils::copy(&val, memPtr, sizeof(val)); return val; + return *(const U16*)memPtr; } + FORCE_INLINE U32 LZ4_read32(const void* memPtr) { - U32 val; Utils::copy(&val, memPtr, sizeof(val)); return val; + return *(const U32*)memPtr; } + FORCE_INLINE reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; Utils::copy(&val, memPtr, sizeof(val)); return val; + return *(const reg_t*)memPtr; +} + +FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) +{ + *(U16*)memPtr = value; +} + +FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) +{ + *(U32*)memPtr = value; +} + +#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 1) +typedef union { + U16 u16; + U32 u32; + reg_t uArch; +} __attribute__((packed)) unalign; +FORCE_INLINE U16 LZ4_read16(const void* ptr) +{ + return ((const unalign*)ptr)->u16; +} +FORCE_INLINE U32 LZ4_read32(const void* ptr) +{ + return ((const unalign*)ptr)->u32; +} +FORCE_INLINE reg_t LZ4_read_ARCH(const void* ptr) +{ + return ((const unalign*)ptr)->uArch; } FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) { - Utils::copy(memPtr, &value, sizeof(value)); + ((unalign*)memPtr)->u16 = value; } FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) { - Utils::copy(memPtr, &value, sizeof(value)); + ((unalign*)memPtr)->u32 = value; +} +#else /* safe and portable */ +FORCE_INLINE U16 LZ4_read16(const void* memPtr) +{ + U16 val; + Utils::copy(&val, memPtr, sizeof(val)); + return val; +} +FORCE_INLINE U32 LZ4_read32(const void* memPtr) +{ + U32 val; + Utils::copy(&val, memPtr, sizeof(val)); + return val; +} +FORCE_INLINE reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; + Utils::copy(&val, memPtr, sizeof(val)); + return val; +} +FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) +{ + Utils::copy(memPtr, &value, sizeof(value)); +} +FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) +{ + Utils::copy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ -FORCE_INLINE U16 LZ4_readLE16(const void *memPtr) +FORCE_INLINE U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE *p = (const BYTE *)memPtr; - return (U16)((U16)p[0] + (p[1] << 8)); - } + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } + else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1] << 8)); + } } -FORCE_INLINE void LZ4_writeLE16(void *memPtr, U16 value) +FORCE_INLINE void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE *p = (BYTE *)memPtr; - p[0] = (BYTE)value; - p[1] = (BYTE)(value >> 8); - } + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } + else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)value; + p[1] = (BYTE)(value >> 8); + } } -FORCE_INLINE void LZ4_copy8(void *dst, const void *src) +FORCE_INLINE void LZ4_copy8(void* dst, const void* src) { - Utils::copy< 8 >(dst, src); + Utils::copy<8>(dst, src); } -FORCE_INLINE void LZ4_wildCopy(void *dstPtr, const void *srcPtr, void *dstEnd) +FORCE_INLINE void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE *d = (BYTE *)dstPtr; - const BYTE *s = (const BYTE *)srcPtr; - BYTE *const e = (BYTE *)dstEnd; - do { - LZ4_copy8(d, s); - d += 8; - s += 8; - } - while (d < e); + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + do { + LZ4_copy8(d, s); + d += 8; + s += 8; + } while (d < e); } #define MINMATCH 4 #define WILDCOPYLENGTH 8 -#define LASTLITERALS 5 -#define MFLIMIT (WILDCOPYLENGTH+MINMATCH) +#define LASTLITERALS 5 +#define MFLIMIT (WILDCOPYLENGTH + MINMATCH) static const int LZ4_minLength = (MFLIMIT + 1); -#define KB *(1 <<10) +#define KB *(1 << 10) // #define MB *(1 <<20) // #define GB *(1U<<30) -#define MAXD_LOG 16 +#define MAXD_LOG 16 #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) #define ML_BITS 4 -#define ML_MASK ((1U<>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif - } - } else /* Big Endian CPU */ { - if (sizeof(val) == 8) { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); -# else - unsigned r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } - } + if (LZ4_isLittleEndian()) { + if (sizeof(val) == 8) { +#if defined(_MSC_VER) && defined(_WIN64) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64(&r, (U64)val); + return (int)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +#else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, + 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, + 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +#endif + } + else /* 32 bits */ { +#if defined(_MSC_VER) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward(&r, (U32)val); + return (int)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +#else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, + 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +#endif + } + } + else /* Big Endian CPU */ { + if (sizeof(val) == 8) { +#if defined(_MSC_VER) && defined(_WIN64) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64(&r, val); + return (unsigned)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll((U64)val) >> 3); +#else + unsigned r; + if (! (val >> 32)) { + r = 4; + } + else { + r = 0; + val >>= 32; + } + if (! (val >> 16)) { + r += 2; + val >>= 8; + } + else { + val >>= 24; + } + r += (! val); + return r; +#endif + } + else /* 32 bits */ { +#if defined(_MSC_VER) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse(&r, (unsigned long)val); + return (unsigned)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +#else + unsigned r; + if (! (val >> 16)) { + r = 2; + val >>= 8; + } + else { + r = 0; + val >>= 24; + } + r += (! val); + return r; +#endif + } + } } #define STEPSIZE sizeof(reg_t) -FORCE_INLINE unsigned LZ4_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *pInLimit) +FORCE_INLINE unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { - const BYTE *const pStart = pIn; + const BYTE* const pStart = pIn; - while (likely(pIn < pInLimit - (STEPSIZE - 1))) { - reg_t const diff = LZ4_read_ARCH(pMatch) ^LZ4_read_ARCH(pIn); - if (!diff) { - pIn += STEPSIZE; - pMatch += STEPSIZE; - continue; - } - pIn += LZ4_NbCommonBytes(diff); - return (unsigned)(pIn - pStart); - } + while (likely(pIn < pInLimit - (STEPSIZE - 1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (! diff) { + pIn += STEPSIZE; + pMatch += STEPSIZE; + continue; + } + pIn += LZ4_NbCommonBytes(diff); + return (unsigned)(pIn - pStart); + } - if ((STEPSIZE == 8) && (pIn < (pInLimit - 3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { - pIn += 4; - pMatch += 4; - } - if ((pIn < (pInLimit - 1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { - pIn += 2; - pMatch += 2; - } - if ((pIn < pInLimit) && (*pMatch == *pIn)) pIn++; - return (unsigned)(pIn - pStart); + if ((STEPSIZE == 8) && (pIn < (pInLimit - 3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { + pIn += 4; + pMatch += 4; + } + if ((pIn < (pInLimit - 1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { + pIn += 2; + pMatch += 2; + } + if ((pIn < pInLimit) && (*pMatch == *pIn)) + pIn++; + return (unsigned)(pIn - pStart); } static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT - 1)); -static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */ +static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */ -typedef enum -{ - notLimited = 0, limitedOutput = 1 -} limitedOutput_directive; -typedef enum -{ - byPtr, byU32, byU16 -} tableType_t; +typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; +typedef enum { byPtr, byU32, byU16 } tableType_t; -typedef enum -{ - noDict = 0, withPrefix64k, usingExtDict -} dict_directive; -typedef enum -{ - noDictIssue = 0, dictSmall -} dictIssue_directive; +typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; -typedef enum -{ - endOnOutputSize = 0, endOnInputSize = 1 -} endCondition_directive; -typedef enum -{ - full = 0, partial = 1 -} earlyEnd_directive; +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; FORCE_INLINE int LZ4_compressBound(int isize) -{ return LZ4_COMPRESSBOUND(isize); } +{ + return LZ4_COMPRESSBOUND(isize); +} FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { - if (tableType == byU16) - return ((sequence * 2654435761U) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1))); - else - return ((sequence * 2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG)); + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG)); } FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - else - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } -FORCE_INLINE U32 LZ4_hashPosition(const void *const p, tableType_t const tableType) +FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if ((sizeof(reg_t) == 8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); - return LZ4_hash4(LZ4_read32(p), tableType); + if ((sizeof(reg_t) == 8) && (tableType != byU16)) + return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); } -FORCE_INLINE void LZ4_putPositionOnHash(const BYTE *p, U32 h, void *tableBase, tableType_t const tableType, const BYTE *srcBase) +FORCE_INLINE void +LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { - switch (tableType) { - case byPtr: { - const BYTE **hashTable = (const BYTE **)tableBase; - hashTable[h] = p; - return; - } - case byU32: { - U32 *hashTable = (U32 *)tableBase; - hashTable[h] = (U32)(p - srcBase); - return; - } - case byU16: { - U16 *hashTable = (U16 *)tableBase; - hashTable[h] = (U16)(p - srcBase); - return; - } - } + switch (tableType) { + case byPtr: { + const BYTE** hashTable = (const BYTE**)tableBase; + hashTable[h] = p; + return; + } + case byU32: { + U32* hashTable = (U32*)tableBase; + hashTable[h] = (U32)(p - srcBase); + return; + } + case byU16: { + U16* hashTable = (U16*)tableBase; + hashTable[h] = (U16)(p - srcBase); + return; + } + } } -FORCE_INLINE void LZ4_putPosition(const BYTE *p, void *tableBase, tableType_t tableType, const BYTE *srcBase) +FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } -FORCE_INLINE const BYTE *LZ4_getPositionOnHash(U32 h, void *tableBase, tableType_t tableType, const BYTE *srcBase) +FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - if (tableType == byPtr) { - const BYTE **hashTable = (const BYTE **)tableBase; - return hashTable[h]; - } - if (tableType == byU32) { - const U32 *const hashTable = (U32 *)tableBase; - return hashTable[h] + srcBase; - } - { - const U16 *const hashTable = (U16 *)tableBase; - return hashTable[h] + srcBase; - } /* default, to ensure a return */ + if (tableType == byPtr) { + const BYTE** hashTable = (const BYTE**)tableBase; + return hashTable[h]; + } + if (tableType == byU32) { + const U32* const hashTable = (U32*)tableBase; + return hashTable[h] + srcBase; + } + { + const U16* const hashTable = (U16*)tableBase; + return hashTable[h] + srcBase; + } /* default, to ensure a return */ } -FORCE_INLINE const BYTE *LZ4_getPosition(const BYTE *p, void *tableBase, tableType_t tableType, const BYTE *srcBase) +FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal *const cctx, - const char *const source, - char *const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { - const BYTE *ip = (const BYTE *)source; - const BYTE *base; - const BYTE *lowLimit; - const BYTE *const lowRefLimit = ip - cctx->dictSize; - const BYTE *const dictionary = cctx->dictionary; - const BYTE *const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE *)source; - const BYTE *anchor = (const BYTE *)source; - const BYTE *const iend = ip + inputSize; - const BYTE *const mflimit = iend - MFLIMIT; - const BYTE *const matchlimit = iend - LASTLITERALS; + const BYTE* ip = (const BYTE*)source; + const BYTE* base; + const BYTE* lowLimit; + const BYTE* const lowRefLimit = ip - cctx->dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*)source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; - BYTE *op = (BYTE *)dest; - BYTE *const olimit = op + maxOutputSize; + BYTE* op = (BYTE*)dest; + BYTE* const olimit = op + maxOutputSize; - U32 forwardH; + U32 forwardH; - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ - switch (dict) { - case noDict: - default: - base = (const BYTE *)source; - lowLimit = (const BYTE *)source; - break; - case withPrefix64k: - base = (const BYTE *)source - cctx->currentOffset; - lowLimit = (const BYTE *)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE *)source - cctx->currentOffset; - lowLimit = (const BYTE *)source; - break; - } - if ((tableType == byU16) && (inputSize >= LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) + return 0; /* Unsupported inputSize, too large (or negative) */ + switch (dict) { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize >= LZ4_64Klimit)) + return 0; /* Size too large (not within 64K limit) */ + if (inputSize < LZ4_minLength) + goto _last_literals; /* Input too small, no compression (all literals) */ - /* First Byte */ - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); + /* First Byte */ + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + ip++; + forwardH = LZ4_hashPosition(ip, tableType); - /* Main Loop */ - for (;;) { - ptrdiff_t refDelta = 0; - const BYTE *match; - BYTE *token; + /* Main Loop */ + for (;;) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; - /* Find a match */ - { - const BYTE *forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); + /* Find a match */ + { + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); - if (unlikely(forwardIp > mflimit)) goto _last_literals; + if (unlikely(forwardIp > mflimit)) + goto _last_literals; - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict == usingExtDict) { - if (match < (const BYTE *)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE *)source; - } - } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict == usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } + else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - } while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match + refDelta) != LZ4_read32(ip))); - } + } while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match + refDelta) != LZ4_read32(ip))); + } - /* Catch up */ - while (((ip > anchor) & (match + refDelta > lowLimit)) && (unlikely(ip[-1] == match[refDelta - 1]))) { - ip--; - match--; - } + /* Catch up */ + while (((ip > anchor) & (match + refDelta > lowLimit)) && (unlikely(ip[-1] == match[refDelta - 1]))) { + ip--; + match--; + } - /* Encode Literals */ - { - unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit))) - return 0; - if (litLength >= RUN_MASK) { - int len = (int)litLength - RUN_MASK; - *token = (RUN_MASK << ML_BITS); - for (; len >= 255; len -= 255) *op++ = 255; - *op++ = (BYTE)len; - } else *token = (BYTE)(litLength << ML_BITS); + /* Encode Literals */ + { + unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength - RUN_MASK; + *token = (RUN_MASK << ML_BITS); + for (; len >= 255; len -= 255) + *op++ = 255; + *op++ = (BYTE)len; + } + else + *token = (BYTE)(litLength << ML_BITS); - /* Copy Literals */ - LZ4_wildCopy(op, anchor, op + litLength); - op += litLength; - } + /* Copy Literals */ + LZ4_wildCopy(op, anchor, op + litLength); + op += litLength; + } - _next_match: - /* Encode Offset */ - LZ4_writeLE16(op, (U16)(ip - match)); - op += 2; + _next_match: + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip - match)); + op += 2; - /* Encode MatchLength */ - { - unsigned matchCode; + /* Encode MatchLength */ + { + unsigned matchCode; - if ((dict == usingExtDict) && (lowLimit == dictionary)) { - const BYTE *limit; - match += refDelta; - limit = ip + (dictEnd - match); - if (limit > matchlimit) limit = matchlimit; - matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip == limit) { - unsigned const more = LZ4_count(ip, (const BYTE *)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } + if ((dict == usingExtDict) && (lowLimit == dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd - match); + if (limit > matchlimit) + limit = matchlimit; + matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip == limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } + else { + matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } - if (outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode >> 8) > olimit))) - return 0; - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4 * 255) op += 4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4 * 255; - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else - *token += (BYTE)(matchCode); - } + if (outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode >> 8) > olimit))) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4 * 255) + op += 4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4 * 255; + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } + else + *token += (BYTE)(matchCode); + } - anchor = ip; + anchor = ip; - /* Test end of chunk */ - if (ip > mflimit) break; + /* Test end of chunk */ + if (ip > mflimit) + break; - /* Fill table */ - LZ4_putPosition(ip - 2, cctx->hashTable, tableType, base); + /* Fill table */ + LZ4_putPosition(ip - 2, cctx->hashTable, tableType, base); - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict == usingExtDict) { - if (match < (const BYTE *)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE *)source; - } - } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) - && (match + MAX_DISTANCE >= ip) - && (LZ4_read32(match + refDelta) == LZ4_read32(ip))) { - token = op++; - *token = 0; - goto _next_match; - } + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict == usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } + else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) && (match + MAX_DISTANCE >= ip) + && (LZ4_read32(match + refDelta) == LZ4_read32(ip))) { + token = op++; + *token = 0; + goto _next_match; + } - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } - _last_literals: - /* Encode Last Literals */ - { - size_t const lastRun = (size_t)(iend - anchor); - if ((outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE *)dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize)) - return 0; - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for (; accumulator >= 255; accumulator -= 255) *op++ = 255; - *op++ = (BYTE)accumulator; - } else { - *op++ = (BYTE)(lastRun << ML_BITS); - } - Utils::copy(op, anchor, lastRun); - op += lastRun; - } +_last_literals: + /* Encode Last Literals */ + { + size_t const lastRun = (size_t)(iend - anchor); + if ((outputLimited) && /* Check output buffer overflow */ + ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize)) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for (; accumulator >= 255; accumulator -= 255) + *op++ = 255; + *op++ = (BYTE)accumulator; + } + else { + *op++ = (BYTE)(lastRun << ML_BITS); + } + Utils::copy(op, anchor, lastRun); + op += lastRun; + } - /* End */ - return (int)(((char *)op) - dest); + /* End */ + return (int)(((char*)op) - dest); } -ZT_INLINE int LZ4_compress_fast_extState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize, int acceleration) +ZT_INLINE int LZ4_compress_fast_extState( + void* state, + const char* source, + char* dest, + int inputSize, + int maxOutputSize, + int acceleration) { - LZ4_stream_t_internal *ctx = &((LZ4_stream_t *)state)->internal_donotuse; - LZ4_resetStream((LZ4_stream_t *)state); - //if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + // if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void *) == 8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } else { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void *) == 8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic( + ctx, + source, + dest, + inputSize, + 0, + notLimited, + byU16, + noDict, + noDictIssue, + acceleration); + else + return LZ4_compress_generic( + ctx, + source, + dest, + inputSize, + 0, + notLimited, + (sizeof(void*) == 8) ? byU32 : byPtr, + noDict, + noDictIssue, + acceleration); + } + else { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic( + ctx, + source, + dest, + inputSize, + maxOutputSize, + limitedOutput, + byU16, + noDict, + noDictIssue, + acceleration); + else + return LZ4_compress_generic( + ctx, + source, + dest, + inputSize, + maxOutputSize, + limitedOutput, + (sizeof(void*) == 8) ? byU32 : byPtr, + noDict, + noDictIssue, + acceleration); + } } -FORCE_INLINE void LZ4_resetStream(LZ4_stream_t *LZ4_stream) +FORCE_INLINE void LZ4_resetStream(LZ4_stream_t* LZ4_stream) { - Utils::zero< sizeof(LZ4_stream_t) >(LZ4_stream); + Utils::zero(LZ4_stream); } FORCE_INLINE int LZ4_decompress_generic( - const char *const source, - char *const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE *const lowPrefix, /* == dest when no prefix */ - const BYTE *const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ ) { - /* Local Variables */ - const BYTE *ip = (const BYTE *)source; - const BYTE *const iend = ip + inputSize; + /* Local Variables */ + const BYTE* ip = (const BYTE*)source; + const BYTE* const iend = ip + inputSize; - BYTE *op = (BYTE *)dest; - BYTE *const oend = op + outputSize; - BYTE *cpy; - BYTE *oexit = op + targetOutputSize; - const BYTE *const lowLimit = lowPrefix - dictSize; + BYTE* op = (BYTE*)dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; - const BYTE *const dictEnd = (const BYTE *)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; + const int dec64table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; - const int safeDecode = (endOnInput == endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + const int safeDecode = (endOnInput == endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + /* Special cases */ + if ((partialDecoding) && (oexit > oend - MFLIMIT)) + oexit = oend - MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize == 0))) + return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; /* Empty output buffer */ + if ((! endOnInput) && (unlikely(outputSize == 0))) + return (*ip == 0 ? 1 : -1); - /* Special cases */ - if ((partialDecoding) && (oexit > oend - MFLIMIT)) oexit = oend - MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize == 0))) return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize == 0))) return (*ip == 0 ? 1 : -1); + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE *match; - size_t offset; + /* get literal length */ + unsigned const token = *ip++; + if ((length = (token >> ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while (likely(endOnInput ? ip < iend - RUN_MASK : 1) & (s == 255)); + if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) + goto _output_error; /* overflow detection */ + if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) + goto _output_error; /* overflow detection */ + } - /* get literal length */ - unsigned const token = *ip++; - if ((length = (token >> ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while (likely(endOnInput ? ip < iend - RUN_MASK : 1) & (s == 255)); - if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) goto _output_error; /* overflow detection */ - if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) goto _output_error; /* overflow detection */ - } + /* copy literals */ + cpy = op + length; + if (((endOnInput) + && ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) || (ip + length > iend - (2 + 1 + LASTLITERALS)))) + || ((! endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { + if (partialDecoding) { + if (cpy > oend) + goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip + length > iend)) + goto _output_error; /* Error : read attempt beyond end of input buffer */ + } + else { + if ((! endOnInput) && (cpy != oend)) + goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) + goto _output_error; /* Error : input must be consumed */ + } + Utils::copy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; + op = cpy; - /* copy literals */ - cpy = op + length; - if (((endOnInput) && ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) || (ip + length > iend - (2 + 1 + LASTLITERALS)))) - || ((!endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { - if (partialDecoding) { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip + length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } else { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - Utils::copy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; + /* get offset */ + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) + goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - /* get offset */ - offset = LZ4_readLE16(ip); - ip += 2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend - LASTLITERALS)) + goto _output_error; + length += s; + } while (s == 255); + if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) + goto _output_error; /* overflow detection */ + } + length += MINMATCH; - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend - LASTLITERALS)) goto _output_error; - length += s; - } while (s == 255); - if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; + /* check external dictionary */ + if ((dict == usingExtDict) && (match < lowPrefix)) { + if (unlikely(op + length > oend - LASTLITERALS)) + goto _output_error; /* doesn't respect parsing restriction */ - /* check external dictionary */ - if ((dict == usingExtDict) && (match < lowPrefix)) { - if (unlikely(op + length > oend - LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + if (length <= (size_t)(lowPrefix - match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix - match), length); + op += length; + } + else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + Utils::copy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) + *op++ = *copyFrom++; + } + else { + Utils::copy(op, lowPrefix, restSize); + op += restSize; + } + } + continue; + } - if (length <= (size_t)(lowPrefix - match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix - match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix - match); - size_t const restSize = length - copySize; - Utils::copy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ - BYTE *const endOfMatch = op + restSize; - const BYTE *copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; - } else { - Utils::copy(op, lowPrefix, restSize); - op += restSize; - } - } - continue; - } + /* copy match within block */ + cpy = op + length; + if (unlikely(offset < 8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + Utils::copy<4>(op + 4, match); + match -= dec64; + } + else { + LZ4_copy8(op, match); + match += 8; + } + op += 8; - /* copy match within block */ - cpy = op + length; - if (unlikely(offset < 8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - Utils::copy< 4 >(op + 4, match); - match -= dec64; - } else { - LZ4_copy8(op, match); - match += 8; - } - op += 8; + if (unlikely(cpy > oend - 12)) { + BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH - 1); + if (cpy > oend - LASTLITERALS) + goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op < cpy) + *op++ = *match++; + } + else { + LZ4_copy8(op, match); + if (length > 16) + LZ4_wildCopy(op + 8, match + 8, cpy); + } + op = cpy; /* correction */ + } - if (unlikely(cpy > oend - 12)) { - BYTE *const oCopyLimit = oend - (WILDCOPYLENGTH - 1); - if (cpy > oend - LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op < cpy) *op++ = *match++; - } else { - LZ4_copy8(op, match); - if (length > 16) LZ4_wildCopy(op + 8, match + 8, cpy); - } - op = cpy; /* correction */ - } + /* end of decoding */ + if (endOnInput) + return (int)(((char*)op) - dest); /* Nb of output bytes decoded */ + else + return (int)(((const char*)ip) - source); /* Nb of input bytes read */ - /* end of decoding */ - if (endOnInput) - return (int)(((char *)op) - dest); /* Nb of output bytes decoded */ - else - return (int)(((const char *)ip) - source); /* Nb of input bytes read */ - - /* Overflow error detected */ - _output_error: - return (int)(-(((const char *)ip) - source)) - 1; +/* Overflow error detected */ +_output_error: + return (int)(-(((const char*)ip) - source)) - 1; } -} // anonymous namespace +} // anonymous namespace -int LZ4_compress_fast(const char *source, char *dest, int inputSize, int maxOutputSize, int acceleration) noexcept +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) noexcept { #if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctx; - void *const ctxPtr = &ctx; + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; #endif - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctxPtr); + FREEMEM(ctxPtr); #endif - return result; + return result; } -int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize) noexcept +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) noexcept { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE *)dest, NULL, 0); + return LZ4_decompress_generic( + source, + dest, + compressedSize, + maxDecompressedSize, + endOnInputSize, + full, + 0, + noDict, + (BYTE*)dest, + NULL, + 0); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/LZ4.hpp b/core/LZ4.hpp index e2dfad89d..2db41b37e 100644 --- a/core/LZ4.hpp +++ b/core/LZ4.hpp @@ -18,12 +18,12 @@ namespace ZeroTier { -#define LZ4_MAX_INPUT_SIZE 0x7E000000 -#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) +#define LZ4_MAX_INPUT_SIZE 0x7E000000 +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16) -int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept; -int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept; +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration = 1) noexcept; +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) noexcept; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Locator.cpp b/core/Locator.cpp index 46b2c86b9..0f41028b1 100644 --- a/core/Locator.cpp +++ b/core/Locator.cpp @@ -12,194 +12,216 @@ /****/ #include "Locator.hpp" + #include "Identity.hpp" #include namespace ZeroTier { -const SharedPtr< const Locator::EndpointAttributes > Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes()); +const SharedPtr + Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes()); -Locator::Locator(const char *const str) noexcept : - __refCount(0) +Locator::Locator(const char* const str) noexcept : __refCount(0) { - if (!fromString(str)) { - m_revision = 0; - m_signer.zero(); - m_endpoints.clear(); - m_signature.clear(); - } + if (! fromString(str)) { + m_revision = 0; + m_signer.zero(); + m_endpoints.clear(); + m_signature.clear(); + } } -bool Locator::add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a) +bool Locator::add(const Endpoint& ep, const SharedPtr& a) { - for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::iterator i(m_endpoints.begin());i!=m_endpoints.end();++i) { - if (i->first == ep) { - i->second = ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT; - return true; - } - } - if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) { - m_endpoints.push_back(std::pair >(ep, ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT)); - return true; - } - return false; + for (Vector > >::iterator i(m_endpoints.begin()); + i != m_endpoints.end(); + ++i) { + if (i->first == ep) { + i->second = ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT; + return true; + } + } + if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) { + m_endpoints.push_back(std::pair >( + ep, + ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT)); + return true; + } + return false; } -bool Locator::sign(const int64_t rev, const Identity &id) noexcept +bool Locator::sign(const int64_t rev, const Identity& id) noexcept { - m_revision = rev; - m_signer = id.address(); + m_revision = rev; + m_signer = id.address(); - m_sortEndpoints(); + m_sortEndpoints(); - uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - const unsigned int signlen = marshal(signdata, true); + uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + const unsigned int signlen = marshal(signdata, true); - const unsigned int siglen = id.sign(signdata, signlen, m_signature.data(), m_signature.capacity()); - if (siglen == 0) - return false; - m_signature.unsafeSetSize(siglen); + const unsigned int siglen = id.sign(signdata, signlen, m_signature.data(), m_signature.capacity()); + if (siglen == 0) + return false; + m_signature.unsafeSetSize(siglen); - return true; + return true; } -bool Locator::verify(const Identity &id) const noexcept +bool Locator::verify(const Identity& id) const noexcept { - try { - if ((m_revision > 0) && (m_signer == id.address())) { - uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - const unsigned int signlen = marshal(signdata, true); - return id.verify(signdata, signlen, m_signature.data(), m_signature.size()); - } - } catch (...) {} // fail verify on any unexpected exception - return false; + try { + if ((m_revision > 0) && (m_signer == id.address())) { + uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + const unsigned int signlen = marshal(signdata, true); + return id.verify(signdata, signlen, m_signature.data(), m_signature.size()); + } + } + catch (...) { + } // fail verify on any unexpected exception + return false; } -char *Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept +char* Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept { - static_assert(ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), "overflow"); - uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - m_signer.toString(s); - s[ZT_ADDRESS_LENGTH_HEX] = '@'; - Utils::b32e(bin, marshal(bin, false), s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); - return s; + static_assert( + ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), + "overflow"); + uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + m_signer.toString(s); + s[ZT_ADDRESS_LENGTH_HEX] = '@'; + Utils::b32e( + bin, + marshal(bin, false), + s + (ZT_ADDRESS_LENGTH_HEX + 1), + ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); + return s; } -bool Locator::fromString(const char *s) noexcept +bool Locator::fromString(const char* s) noexcept { - if (!s) - return false; - if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1)) - return false; - uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - const int bl = Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), bin, ZT_LOCATOR_MARSHAL_SIZE_MAX); - if ((bl <= 0) || (bl > ZT_LOCATOR_MARSHAL_SIZE_MAX)) - return false; - return unmarshal(bin, bl) > 0; + if (! s) + return false; + if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1)) + return false; + uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + const int bl = Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), bin, ZT_LOCATOR_MARSHAL_SIZE_MAX); + if ((bl <= 0) || (bl > ZT_LOCATOR_MARSHAL_SIZE_MAX)) + return false; + return unmarshal(bin, bl) > 0; } int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept { - Utils::storeBigEndian(data, (uint64_t) m_revision); - m_signer.copyTo(data + 8); - int p = 8 + ZT_ADDRESS_LENGTH; + Utils::storeBigEndian(data, (uint64_t)m_revision); + m_signer.copyTo(data + 8); + int p = 8 + ZT_ADDRESS_LENGTH; - Utils::storeBigEndian(data + p, (uint16_t)m_endpoints.size()); - p += 2; - for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) { - int l = e->first.marshal(data + p); - if (l <= 0) - return -1; - p += l; + Utils::storeBigEndian(data + p, (uint16_t)m_endpoints.size()); + p += 2; + for (Vector > >::const_iterator e(m_endpoints.begin()); + e != m_endpoints.end(); + ++e) { + int l = e->first.marshal(data + p); + if (l <= 0) + return -1; + p += l; - l = (int)e->second->data[0]; - if (l > 0) { - Utils::copy(data + p, e->second->data, (unsigned int)l); - p += l; - } else { - data[p++] = 0; - } - } + l = (int)e->second->data[0]; + if (l > 0) { + Utils::copy(data + p, e->second->data, (unsigned int)l); + p += l; + } + else { + data[p++] = 0; + } + } - Utils::storeMachineEndian< uint16_t >(data + p, 0); // length of meta-data, currently always 0 - p += 2; + Utils::storeMachineEndian(data + p, 0); // length of meta-data, currently always 0 + p += 2; - if (!excludeSignature) { - Utils::storeBigEndian(data + p, (uint16_t) m_signature.size()); - p += 2; - Utils::copy(data + p, m_signature.data(), m_signature.size()); - p += (int) m_signature.size(); - } + if (! excludeSignature) { + Utils::storeBigEndian(data + p, (uint16_t)m_signature.size()); + p += 2; + Utils::copy(data + p, m_signature.data(), m_signature.size()); + p += (int)m_signature.size(); + } - return p; + return p; } -int Locator::unmarshal(const uint8_t *data, const int len) noexcept +int Locator::unmarshal(const uint8_t* data, const int len) noexcept { - if (unlikely(len < (8 + ZT_ADDRESS_LENGTH))) - return -1; - m_revision = (int64_t)Utils::loadBigEndian(data); - m_signer.setTo(data + 8); - int p = 8 + ZT_ADDRESS_LENGTH; + if (unlikely(len < (8 + ZT_ADDRESS_LENGTH))) + return -1; + m_revision = (int64_t)Utils::loadBigEndian(data); + m_signer.setTo(data + 8); + int p = 8 + ZT_ADDRESS_LENGTH; - if (unlikely(p + 2) > len) - return -1; - unsigned int endpointCount = Utils::loadBigEndian(data + p); - p += 2; - if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)) - return -1; - m_endpoints.resize(endpointCount); - m_endpoints.shrink_to_fit(); - for (unsigned int i = 0;i < endpointCount;++i) { - int l = m_endpoints[i].first.unmarshal(data + p, len - p); - if (l <= 0) - return -1; - p += l; + if (unlikely(p + 2) > len) + return -1; + unsigned int endpointCount = Utils::loadBigEndian(data + p); + p += 2; + if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)) + return -1; + m_endpoints.resize(endpointCount); + m_endpoints.shrink_to_fit(); + for (unsigned int i = 0; i < endpointCount; ++i) { + int l = m_endpoints[i].first.unmarshal(data + p, len - p); + if (l <= 0) + return -1; + p += l; - if (unlikely(p + 1) > len) - return -1; - l = (int)data[p]; - if (l <= 0) { - m_endpoints[i].second = EndpointAttributes::DEFAULT; - ++p; - } else { - m_endpoints[i].second.set(new EndpointAttributes()); - Utils::copy(const_cast< uint8_t * >(m_endpoints[i].second->data), data + p, (unsigned int)l); - p += l; - } - } + if (unlikely(p + 1) > len) + return -1; + l = (int)data[p]; + if (l <= 0) { + m_endpoints[i].second = EndpointAttributes::DEFAULT; + ++p; + } + else { + m_endpoints[i].second.set(new EndpointAttributes()); + Utils::copy(const_cast(m_endpoints[i].second->data), data + p, (unsigned int)l); + p += l; + } + } - if (unlikely((p + 2) > len)) - return -1; - p += 2 + (int)Utils::loadBigEndian(data + p); + if (unlikely((p + 2) > len)) + return -1; + p += 2 + (int)Utils::loadBigEndian(data + p); - if (unlikely((p + 2) > len)) - return -1; - const unsigned int siglen = Utils::loadBigEndian(data + p); - p += 2; - if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int)siglen) > len))) - return -1; - m_signature.unsafeSetSize(siglen); - Utils::copy(m_signature.data(), data + p, siglen); - p += (int)siglen; - if (unlikely(p > len)) - return -1; + if (unlikely((p + 2) > len)) + return -1; + const unsigned int siglen = Utils::loadBigEndian(data + p); + p += 2; + if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int)siglen) > len))) + return -1; + m_signature.unsafeSetSize(siglen); + Utils::copy(m_signature.data(), data + p, siglen); + p += (int)siglen; + if (unlikely(p > len)) + return -1; - m_sortEndpoints(); + m_sortEndpoints(); - return p; + return p; } -struct p_SortByEndpoint -{ - // There can't be more than one of the same endpoint, so only need to sort - // by endpoint. - ZT_INLINE bool operator()(const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &a,const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &b) const noexcept - { return a.first < b.first; } +struct p_SortByEndpoint { + // There can't be more than one of the same endpoint, so only need to sort + // by endpoint. + ZT_INLINE bool operator()( + const std::pair >& a, + const std::pair >& b) const noexcept + { + return a.first < b.first; + } }; void Locator::m_sortEndpoints() noexcept -{ std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); } +{ + std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); +} -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Locator.hpp b/core/Locator.hpp index bfb27b2d2..6ff33a5ba 100644 --- a/core/Locator.hpp +++ b/core/Locator.hpp @@ -15,13 +15,13 @@ #define ZT_LOCATOR_HPP #include "Constants.hpp" -#include "Endpoint.hpp" -#include "Identity.hpp" -#include "TriviallyCopyable.hpp" -#include "SharedPtr.hpp" -#include "FCV.hpp" #include "Containers.hpp" #include "Dictionary.hpp" +#include "Endpoint.hpp" +#include "FCV.hpp" +#include "Identity.hpp" +#include "SharedPtr.hpp" +#include "TriviallyCopyable.hpp" /** * Maximum size of endpoint attributes dictionary plus one byte for size. @@ -35,7 +35,10 @@ */ #define ZT_LOCATOR_MAX_ENDPOINTS 16 -#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + ZT_ADDRESS_LENGTH + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * (ZT_ENDPOINT_MARSHAL_SIZE_MAX + ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE)) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) +#define ZT_LOCATOR_MARSHAL_SIZE_MAX \ + (8 + ZT_ADDRESS_LENGTH + 2 \ + + (ZT_LOCATOR_MAX_ENDPOINTS * (ZT_ENDPOINT_MARSHAL_SIZE_MAX + ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE)) + 2 + 2 \ + + ZT_SIGNATURE_BUFFER_SIZE) /** * Maximum size of a string format Locator (this is way larger than needed) @@ -50,194 +53,223 @@ namespace ZeroTier { * A locator contains long-lived endpoints for a node such as IP/port pairs, * URLs, or other nodes, and is signed by the node it describes. */ -class Locator -{ - friend class SharedPtr< Locator >; - friend class SharedPtr< const Locator >; +class Locator { + friend class SharedPtr; + friend class SharedPtr; -public: - /** - * Attributes of an endpoint in this locator - * - * This is specified for future use, but there are currently no attributes - * defined. A Dictionary is used for serialization for extensibility. - */ - struct EndpointAttributes - { - friend class SharedPtr< Locator::EndpointAttributes >; - friend class SharedPtr< const Locator::EndpointAttributes >; + public: + /** + * Attributes of an endpoint in this locator + * + * This is specified for future use, but there are currently no attributes + * defined. A Dictionary is used for serialization for extensibility. + */ + struct EndpointAttributes { + friend class SharedPtr; + friend class SharedPtr; - /** - * Default endpoint attributes - */ - static const SharedPtr< const Locator::EndpointAttributes > DEFAULT; + /** + * Default endpoint attributes + */ + static const SharedPtr DEFAULT; - /** - * Raw attributes data in the form of a dictionary prefixed by its size. - * - * The maximum size of attributes is 255, which is more than enough for - * tiny things like bandwidth and priority. - */ - uint8_t data[ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE]; + /** + * Raw attributes data in the form of a dictionary prefixed by its size. + * + * The maximum size of attributes is 255, which is more than enough for + * tiny things like bandwidth and priority. + */ + uint8_t data[ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE]; - ZT_INLINE EndpointAttributes() noexcept - { Utils::zero< ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE >(data); } + ZT_INLINE EndpointAttributes() noexcept + { + Utils::zero(data); + } - ZT_INLINE bool operator==(const EndpointAttributes &a) const noexcept - { return ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) == 0)); } + ZT_INLINE bool operator==(const EndpointAttributes& a) const noexcept + { + return ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) == 0)); + } - ZT_INLINE bool operator<(const EndpointAttributes &a) const noexcept - { return ((data[0] < a.data[0]) || ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) < 0))); } + ZT_INLINE bool operator<(const EndpointAttributes& a) const noexcept + { + return ((data[0] < a.data[0]) || ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) < 0))); + } - ZT_INLINE bool operator!=(const EndpointAttributes &a) const noexcept - { return !(*this == a); } + ZT_INLINE bool operator!=(const EndpointAttributes& a) const noexcept + { + return ! (*this == a); + } - ZT_INLINE bool operator>(const EndpointAttributes &a) const noexcept - { return (a < *this); } + ZT_INLINE bool operator>(const EndpointAttributes& a) const noexcept + { + return (a < *this); + } - ZT_INLINE bool operator<=(const EndpointAttributes &a) const noexcept - { return !(a < *this); } + ZT_INLINE bool operator<=(const EndpointAttributes& a) const noexcept + { + return ! (a < *this); + } - ZT_INLINE bool operator>=(const EndpointAttributes &a) const noexcept - { return !(*this < a); } + ZT_INLINE bool operator>=(const EndpointAttributes& a) const noexcept + { + return ! (*this < a); + } - private: - std::atomic< int > __refCount; - }; + private: + std::atomic __refCount; + }; - ZT_INLINE Locator() noexcept: - m_revision(0) - {} + ZT_INLINE Locator() noexcept : m_revision(0) + { + } - ZT_INLINE Locator(const Locator &l) noexcept: - m_revision(l.m_revision), - m_signer(l.m_signer), - m_endpoints(l.m_endpoints), - m_signature(l.m_signature), - __refCount(0) - {} + ZT_INLINE Locator(const Locator& l) noexcept + : m_revision(l.m_revision) + , m_signer(l.m_signer) + , m_endpoints(l.m_endpoints) + , m_signature(l.m_signature) + , __refCount(0) + { + } - explicit Locator(const char *const str) noexcept; + explicit Locator(const char* const str) noexcept; - /** - * @return Timestamp (a.k.a. revision number) set by Location signer - */ - ZT_INLINE int64_t revision() const noexcept - { return m_revision; } + /** + * @return Timestamp (a.k.a. revision number) set by Location signer + */ + ZT_INLINE int64_t revision() const noexcept + { + return m_revision; + } - /** - * @return ZeroTier address of signer - */ - ZT_INLINE Address signer() const noexcept - { return m_signer; } + /** + * @return ZeroTier address of signer + */ + ZT_INLINE Address signer() const noexcept + { + return m_signer; + } - /** - * @return Endpoints specified in locator - */ - ZT_INLINE const Vector >> &endpoints() const noexcept - { return m_endpoints; } + /** + * @return Endpoints specified in locator + */ + ZT_INLINE const Vector > >& endpoints() const noexcept + { + return m_endpoints; + } - /** - * @return Signature data - */ - ZT_INLINE const FCV< uint8_t, ZT_SIGNATURE_BUFFER_SIZE > &signature() const noexcept - { return m_signature; } + /** + * @return Signature data + */ + ZT_INLINE const FCV& signature() const noexcept + { + return m_signature; + } - /** - * Add an endpoint to this locator - * - * This doesn't check for the presence of the endpoint, so take - * care not to add duplicates. - * - * @param ep Endpoint to add - * @param a Endpoint attributes or NULL to use default - * @return True if endpoint was added (or already present), false if locator is full - */ - bool add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a); + /** + * Add an endpoint to this locator + * + * This doesn't check for the presence of the endpoint, so take + * care not to add duplicates. + * + * @param ep Endpoint to add + * @param a Endpoint attributes or NULL to use default + * @return True if endpoint was added (or already present), false if locator is full + */ + bool add(const Endpoint& ep, const SharedPtr& a); - /** - * Sign this locator - * - * This sets timestamp, sorts endpoints so that the same set of endpoints - * will always produce the same locator, and signs. - * - * @param id Identity that includes private key - * @return True if signature successful - */ - bool sign(int64_t rev, const Identity &id) noexcept; + /** + * Sign this locator + * + * This sets timestamp, sorts endpoints so that the same set of endpoints + * will always produce the same locator, and signs. + * + * @param id Identity that includes private key + * @return True if signature successful + */ + bool sign(int64_t rev, const Identity& id) noexcept; - /** - * Verify this Locator's validity and signature - * - * @param id Identity corresponding to hash - * @return True if valid and signature checks out - */ - bool verify(const Identity &id) const noexcept; + /** + * Verify this Locator's validity and signature + * + * @param id Identity corresponding to hash + * @return True if valid and signature checks out + */ + bool verify(const Identity& id) const noexcept; - /** - * Convert this locator to a string - * - * @param s String buffer - * @return Pointer to buffer - */ - char *toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept; + /** + * Convert this locator to a string + * + * @param s String buffer + * @return Pointer to buffer + */ + char* toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept; - ZT_INLINE String toString() const - { - char tmp[ZT_LOCATOR_STRING_SIZE_MAX]; - return String(toString(tmp)); - } + ZT_INLINE String toString() const + { + char tmp[ZT_LOCATOR_STRING_SIZE_MAX]; + return String(toString(tmp)); + } - /** - * Decode a string format locator - * - * @param s Locator from toString() - * @return True if format was valid - */ - bool fromString(const char *s) noexcept; + /** + * Decode a string format locator + * + * @param s Locator from toString() + * @return True if format was valid + */ + bool fromString(const char* s) noexcept; - explicit ZT_INLINE operator bool() const noexcept - { return m_revision > 0; } + explicit ZT_INLINE operator bool() const noexcept + { + return m_revision > 0; + } - static constexpr int marshalSizeMax() noexcept - { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_LOCATOR_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; - ZT_INLINE bool operator==(const Locator &l) const noexcept - { - const unsigned long es = (unsigned long)m_endpoints.size(); - if ((m_revision == l.m_revision) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size()) && (m_signature == l.m_signature)) { - for (unsigned long i = 0; i < es; ++i) { - if (m_endpoints[i].first != l.m_endpoints[i].first) - return false; - if (!m_endpoints[i].second) { - if (l.m_endpoints[i].second) - return false; - } else { - if ((!l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second))) - return false; - } - } - return true; - } - return false; - } + ZT_INLINE bool operator==(const Locator& l) const noexcept + { + const unsigned long es = (unsigned long)m_endpoints.size(); + if ((m_revision == l.m_revision) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size()) + && (m_signature == l.m_signature)) { + for (unsigned long i = 0; i < es; ++i) { + if (m_endpoints[i].first != l.m_endpoints[i].first) + return false; + if (! m_endpoints[i].second) { + if (l.m_endpoints[i].second) + return false; + } + else { + if ((! l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second))) + return false; + } + } + return true; + } + return false; + } - ZT_INLINE bool operator!=(const Locator &l) const noexcept - { return !(*this == l); } + ZT_INLINE bool operator!=(const Locator& l) const noexcept + { + return ! (*this == l); + } -private: - void m_sortEndpoints() noexcept; + private: + void m_sortEndpoints() noexcept; - int64_t m_revision; - Address m_signer; - Vector >> m_endpoints; - FCV< uint8_t, ZT_SIGNATURE_BUFFER_SIZE > m_signature; - std::atomic< int > __refCount; + int64_t m_revision; + Address m_signer; + Vector > > m_endpoints; + FCV m_signature; + std::atomic __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/MAC.hpp b/core/MAC.hpp index 131e828dc..159893d83 100644 --- a/core/MAC.hpp +++ b/core/MAC.hpp @@ -14,258 +14,315 @@ #ifndef ZT_MAC_HPP #define ZT_MAC_HPP -#include "Constants.hpp" -#include "Utils.hpp" #include "Address.hpp" -#include "TriviallyCopyable.hpp" +#include "Constants.hpp" #include "Containers.hpp" +#include "TriviallyCopyable.hpp" +#include "Utils.hpp" namespace ZeroTier { /** * 48-byte Ethernet MAC address */ -class MAC : public TriviallyCopyable -{ -public: - ZT_INLINE MAC() noexcept: m_mac(0ULL) - {} +class MAC : public TriviallyCopyable { + public: + ZT_INLINE MAC() noexcept : m_mac(0ULL) + { + } - ZT_INLINE MAC(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d, const uint8_t e, const uint8_t f) noexcept: - m_mac((((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) | (((uint64_t)e) << 8U) | ((uint64_t)f)) - {} + ZT_INLINE + MAC(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d, const uint8_t e, const uint8_t f) noexcept + : m_mac( + (((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) + | (((uint64_t)e) << 8U) | ((uint64_t)f)) + { + } - explicit ZT_INLINE MAC(const uint64_t m) noexcept: - m_mac(m) - {} + explicit ZT_INLINE MAC(const uint64_t m) noexcept : m_mac(m) + { + } - explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept - { setTo(b); } + explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept + { + setTo(b); + } - ZT_INLINE MAC(const Address &ztaddr, const uint64_t nwid) noexcept - { fromAddress(ztaddr, nwid); } + ZT_INLINE MAC(const Address& ztaddr, const uint64_t nwid) noexcept + { + fromAddress(ztaddr, nwid); + } - /** - * @return MAC in 64-bit integer - */ - ZT_INLINE uint64_t toInt() const noexcept - { return m_mac; } + /** + * @return MAC in 64-bit integer + */ + ZT_INLINE uint64_t toInt() const noexcept + { + return m_mac; + } - /** - * Set MAC to zero - */ - ZT_INLINE void zero() noexcept - { m_mac = 0ULL; } + /** + * Set MAC to zero + */ + ZT_INLINE void zero() noexcept + { + m_mac = 0ULL; + } - /** - * @param bits Raw MAC in big-endian byte order - * @param len Length, must be >= 6 or result is zero - */ - ZT_INLINE void setTo(const uint8_t b[6]) noexcept - { m_mac = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) | ((uint64_t)b[4] << 8U) | (uint64_t)b[5]; } + /** + * @param bits Raw MAC in big-endian byte order + * @param len Length, must be >= 6 or result is zero + */ + ZT_INLINE void setTo(const uint8_t b[6]) noexcept + { + m_mac = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) + | ((uint64_t)b[4] << 8U) | (uint64_t)b[5]; + } - /** - * @param buf Destination buffer for MAC in big-endian byte order - * @param len Length of buffer, must be >= 6 or nothing is copied - */ - ZT_INLINE void copyTo(uint8_t b[6]) const noexcept - { - b[0] = (uint8_t)(m_mac >> 40U); - b[1] = (uint8_t)(m_mac >> 32U); - b[2] = (uint8_t)(m_mac >> 24U); - b[3] = (uint8_t)(m_mac >> 16U); - b[4] = (uint8_t)(m_mac >> 8U); - b[5] = (uint8_t)m_mac; - } + /** + * @param buf Destination buffer for MAC in big-endian byte order + * @param len Length of buffer, must be >= 6 or nothing is copied + */ + ZT_INLINE void copyTo(uint8_t b[6]) const noexcept + { + b[0] = (uint8_t)(m_mac >> 40U); + b[1] = (uint8_t)(m_mac >> 32U); + b[2] = (uint8_t)(m_mac >> 24U); + b[3] = (uint8_t)(m_mac >> 16U); + b[4] = (uint8_t)(m_mac >> 8U); + b[5] = (uint8_t)m_mac; + } - /** - * @return True if this is broadcast (all 0xff) - */ - ZT_INLINE bool isBroadcast() const noexcept - { return m_mac; } + /** + * @return True if this is broadcast (all 0xff) + */ + ZT_INLINE bool isBroadcast() const noexcept + { + return m_mac; + } - /** - * @return True if this is a multicast MAC - */ - ZT_INLINE bool isMulticast() const noexcept - { return ((m_mac & 0x010000000000ULL) != 0ULL); } + /** + * @return True if this is a multicast MAC + */ + ZT_INLINE bool isMulticast() const noexcept + { + return ((m_mac & 0x010000000000ULL) != 0ULL); + } - /** - * Set this MAC to a MAC derived from an address and a network ID - * - * @param ztaddr ZeroTier address - * @param nwid 64-bit network ID - */ - ZT_INLINE void fromAddress(const Address &ztaddr, uint64_t nwid) noexcept - { - uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40U; - m |= ztaddr.toInt(); // a is 40 bits - m ^= ((nwid >> 8U) & 0xffU) << 32U; - m ^= ((nwid >> 16U) & 0xffU) << 24U; - m ^= ((nwid >> 24U) & 0xffU) << 16U; - m ^= ((nwid >> 32U) & 0xffU) << 8U; - m ^= (nwid >> 40U) & 0xffU; - m_mac = m; - } + /** + * Set this MAC to a MAC derived from an address and a network ID + * + * @param ztaddr ZeroTier address + * @param nwid 64-bit network ID + */ + ZT_INLINE void fromAddress(const Address& ztaddr, uint64_t nwid) noexcept + { + uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40U; + m |= ztaddr.toInt(); // a is 40 bits + m ^= ((nwid >> 8U) & 0xffU) << 32U; + m ^= ((nwid >> 16U) & 0xffU) << 24U; + m ^= ((nwid >> 24U) & 0xffU) << 16U; + m ^= ((nwid >> 32U) & 0xffU) << 8U; + m ^= (nwid >> 40U) & 0xffU; + m_mac = m; + } - /** - * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast) - * - * This just XORs the next-lest-significant 5 bytes of the network ID again to unmask. - * - * @param nwid Network ID - */ - ZT_INLINE Address toAddress(uint64_t nwid) const noexcept - { - uint64_t a = m_mac & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address - a ^= ((nwid >> 8U) & 0xffU) << 32U; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it - a ^= ((nwid >> 16U) & 0xffU) << 24U; - a ^= ((nwid >> 24U) & 0xffU) << 16U; - a ^= ((nwid >> 32U) & 0xffU) << 8U; - a ^= (nwid >> 40U) & 0xffU; - return Address(a); - } + /** + * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast) + * + * This just XORs the next-lest-significant 5 bytes of the network ID again to unmask. + * + * @param nwid Network ID + */ + ZT_INLINE Address toAddress(uint64_t nwid) const noexcept + { + uint64_t a = m_mac & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address + a ^= ((nwid >> 8U) & 0xffU) + << 32U; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it + a ^= ((nwid >> 16U) & 0xffU) << 24U; + a ^= ((nwid >> 24U) & 0xffU) << 16U; + a ^= ((nwid >> 32U) & 0xffU) << 8U; + a ^= (nwid >> 40U) & 0xffU; + return Address(a); + } - /** - * @param nwid Network ID - * @return First octet of MAC for this network - */ - static ZT_INLINE unsigned char firstOctetForNetwork(uint64_t nwid) noexcept - { - const uint8_t a = ((uint8_t)(nwid & 0xfeU) | 0x02U); // locally administered, not multicast, from LSB of network ID - return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux - } + /** + * @param nwid Network ID + * @return First octet of MAC for this network + */ + static ZT_INLINE unsigned char firstOctetForNetwork(uint64_t nwid) noexcept + { + const uint8_t a = + ((uint8_t)(nwid & 0xfeU) | 0x02U); // locally administered, not multicast, from LSB of network ID + return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular + // virtualization engines... seems de-facto standard on Linux + } - /** - * @param i Value from 0 to 5 (inclusive) - * @return Byte at said position (address interpreted in big-endian order) - */ - ZT_INLINE uint8_t operator[](unsigned int i) const noexcept - { return (uint8_t)(m_mac >> (unsigned int)(40 - (i * 8))); } + /** + * @param i Value from 0 to 5 (inclusive) + * @return Byte at said position (address interpreted in big-endian order) + */ + ZT_INLINE uint8_t operator[](unsigned int i) const noexcept + { + return (uint8_t)(m_mac >> (unsigned int)(40 - (i * 8))); + } - /** - * @return 6, which is the number of bytes in a MAC, for container compliance - */ - ZT_INLINE unsigned int size() const noexcept - { return 6; } + /** + * @return 6, which is the number of bytes in a MAC, for container compliance + */ + ZT_INLINE unsigned int size() const noexcept + { + return 6; + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)Utils::hash64(m_mac); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)Utils::hash64(m_mac); + } - ZT_INLINE operator bool() const noexcept - { return (m_mac != 0ULL); } + ZT_INLINE operator bool() const noexcept + { + return (m_mac != 0ULL); + } - ZT_INLINE operator uint64_t() const noexcept - { return m_mac; } + ZT_INLINE operator uint64_t() const noexcept + { + return m_mac; + } - /** - * Convert this MAC to a standard format colon-separated hex string - * - * @param buf Buffer to store string - * @return Pointer to buf - */ - ZT_INLINE char *toString(char buf[18]) const noexcept - { - buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU]; - buf[1] = Utils::HEXCHARS[(m_mac >> 40U) & 0xfU]; - buf[2] = ':'; - buf[3] = Utils::HEXCHARS[(m_mac >> 36U) & 0xfU]; - buf[4] = Utils::HEXCHARS[(m_mac >> 32U) & 0xfU]; - buf[5] = ':'; - buf[6] = Utils::HEXCHARS[(m_mac >> 28U) & 0xfU]; - buf[7] = Utils::HEXCHARS[(m_mac >> 24U) & 0xfU]; - buf[8] = ':'; - buf[9] = Utils::HEXCHARS[(m_mac >> 20U) & 0xfU]; - buf[10] = Utils::HEXCHARS[(m_mac >> 16U) & 0xfU]; - buf[11] = ':'; - buf[12] = Utils::HEXCHARS[(m_mac >> 12U) & 0xfU]; - buf[13] = Utils::HEXCHARS[(m_mac >> 8U) & 0xfU]; - buf[14] = ':'; - buf[15] = Utils::HEXCHARS[(m_mac >> 4U) & 0xfU]; - buf[16] = Utils::HEXCHARS[m_mac & 0xfU]; - buf[17] = (char)0; - return buf; - } + /** + * Convert this MAC to a standard format colon-separated hex string + * + * @param buf Buffer to store string + * @return Pointer to buf + */ + ZT_INLINE char* toString(char buf[18]) const noexcept + { + buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU]; + buf[1] = Utils::HEXCHARS[(m_mac >> 40U) & 0xfU]; + buf[2] = ':'; + buf[3] = Utils::HEXCHARS[(m_mac >> 36U) & 0xfU]; + buf[4] = Utils::HEXCHARS[(m_mac >> 32U) & 0xfU]; + buf[5] = ':'; + buf[6] = Utils::HEXCHARS[(m_mac >> 28U) & 0xfU]; + buf[7] = Utils::HEXCHARS[(m_mac >> 24U) & 0xfU]; + buf[8] = ':'; + buf[9] = Utils::HEXCHARS[(m_mac >> 20U) & 0xfU]; + buf[10] = Utils::HEXCHARS[(m_mac >> 16U) & 0xfU]; + buf[11] = ':'; + buf[12] = Utils::HEXCHARS[(m_mac >> 12U) & 0xfU]; + buf[13] = Utils::HEXCHARS[(m_mac >> 8U) & 0xfU]; + buf[14] = ':'; + buf[15] = Utils::HEXCHARS[(m_mac >> 4U) & 0xfU]; + buf[16] = Utils::HEXCHARS[m_mac & 0xfU]; + buf[17] = (char)0; + return buf; + } - ZT_INLINE String toString() const - { - char tmp[18]; - return String(toString(tmp)); - } + ZT_INLINE String toString() const + { + char tmp[18]; + return String(toString(tmp)); + } - /** - * Parse a MAC address in hex format with or without : separators and ignoring non-hex characters. - * - * @param s String to parse - */ - ZT_INLINE void fromString(const char *s) noexcept - { - m_mac = 0; - if (s) { - while (*s) { - uint64_t c; - const char hc = *s++; - if ((hc >= 48) && (hc <= 57)) - c = (uint64_t)hc - 48; - else if ((hc >= 97) && (hc <= 102)) - c = (uint64_t)hc - 87; - else if ((hc >= 65) && (hc <= 70)) - c = (uint64_t)hc - 55; - else continue; - m_mac = (m_mac << 4U) | c; - } - m_mac &= 0xffffffffffffULL; - } - } + /** + * Parse a MAC address in hex format with or without : separators and ignoring non-hex characters. + * + * @param s String to parse + */ + ZT_INLINE void fromString(const char* s) noexcept + { + m_mac = 0; + if (s) { + while (*s) { + uint64_t c; + const char hc = *s++; + if ((hc >= 48) && (hc <= 57)) + c = (uint64_t)hc - 48; + else if ((hc >= 97) && (hc <= 102)) + c = (uint64_t)hc - 87; + else if ((hc >= 65) && (hc <= 70)) + c = (uint64_t)hc - 55; + else + continue; + m_mac = (m_mac << 4U) | c; + } + m_mac &= 0xffffffffffffULL; + } + } - ZT_INLINE MAC &operator=(const uint64_t m) noexcept - { - m_mac = m; - return *this; - } + ZT_INLINE MAC& operator=(const uint64_t m) noexcept + { + m_mac = m; + return *this; + } - ZT_INLINE bool operator==(const MAC &m) const noexcept - { return (m_mac == m.m_mac); } + ZT_INLINE bool operator==(const MAC& m) const noexcept + { + return (m_mac == m.m_mac); + } - ZT_INLINE bool operator!=(const MAC &m) const noexcept - { return (m_mac != m.m_mac); } + ZT_INLINE bool operator!=(const MAC& m) const noexcept + { + return (m_mac != m.m_mac); + } - ZT_INLINE bool operator<(const MAC &m) const noexcept - { return (m_mac < m.m_mac); } + ZT_INLINE bool operator<(const MAC& m) const noexcept + { + return (m_mac < m.m_mac); + } - ZT_INLINE bool operator<=(const MAC &m) const noexcept - { return (m_mac <= m.m_mac); } + ZT_INLINE bool operator<=(const MAC& m) const noexcept + { + return (m_mac <= m.m_mac); + } - ZT_INLINE bool operator>(const MAC &m) const noexcept - { return (m_mac > m.m_mac); } + ZT_INLINE bool operator>(const MAC& m) const noexcept + { + return (m_mac > m.m_mac); + } - ZT_INLINE bool operator>=(const MAC &m) const noexcept - { return (m_mac >= m.m_mac); } + ZT_INLINE bool operator>=(const MAC& m) const noexcept + { + return (m_mac >= m.m_mac); + } - ZT_INLINE bool operator==(const uint64_t m) const noexcept - { return (m_mac == m); } + ZT_INLINE bool operator==(const uint64_t m) const noexcept + { + return (m_mac == m); + } - ZT_INLINE bool operator!=(const uint64_t m) const noexcept - { return (m_mac != m); } + ZT_INLINE bool operator!=(const uint64_t m) const noexcept + { + return (m_mac != m); + } - ZT_INLINE bool operator<(const uint64_t m) const noexcept - { return (m_mac < m); } + ZT_INLINE bool operator<(const uint64_t m) const noexcept + { + return (m_mac < m); + } - ZT_INLINE bool operator<=(const uint64_t m) const noexcept - { return (m_mac <= m); } + ZT_INLINE bool operator<=(const uint64_t m) const noexcept + { + return (m_mac <= m); + } - ZT_INLINE bool operator>(const uint64_t m) const noexcept - { return (m_mac > m); } + ZT_INLINE bool operator>(const uint64_t m) const noexcept + { + return (m_mac > m); + } - ZT_INLINE bool operator>=(const uint64_t m) const noexcept - { return (m_mac >= m); } + ZT_INLINE bool operator>=(const uint64_t m) const noexcept + { + return (m_mac >= m); + } -private: - uint64_t m_mac; + private: + uint64_t m_mac; }; static_assert(sizeof(MAC) == sizeof(uint64_t), "MAC contains unnecessary padding"); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/MIMC52.cpp b/core/MIMC52.cpp index 4b1e73d02..bd5f8bd47 100644 --- a/core/MIMC52.cpp +++ b/core/MIMC52.cpp @@ -11,37 +11,131 @@ */ /****/ -#include "Constants.hpp" -#include "AES.hpp" #include "MIMC52.hpp" +#include "AES.hpp" +#include "Constants.hpp" + namespace { // Largest 1024 primes of form 6k + 5 and less than 2^52. Only the least significant 32 // bits need to be here, as the most significant bits are all 1. -const uint32_t ZT_MIMC52_PRIMES[1024] = {4294895267, 4294895477, 4294895513, 4294895519, 4294895543, 4294895567, 4294895657, 4294895711, 4294895777, 4294895861, 4294895909, 4294895921, 4294895969, 4294896011, 4294896149, 4294896227, 4294896401, 4294896473, 4294896527, 4294896563, 4294896653, 4294896731, 4294896863, 4294896899, 4294896983, 4294897037, 4294897103, 4294897331, 4294897349, 4294897451, 4294897571, 4294897661, 4294897703, 4294897757, 4294897793, 4294897811, 4294897817, 4294897829, 4294897877, 4294897919, 4294897991, 4294898027, 4294898129, 4294898153, 4294898231, 4294898273, - 4294898279, 4294898291, 4294898363, 4294898369, 4294898417, 4294898423, 4294898453, 4294898489, 4294898573, 4294898579, 4294898639, 4294898693, 4294898747, 4294898759, 4294898867, 4294898879, 4294898909, 4294898921, 4294898933, 4294899011, 4294899041, 4294899047, 4294899203, 4294899221, 4294899227, 4294899287, 4294899341, 4294899431, 4294899509, 4294899533, 4294899539, 4294899551, 4294899629, 4294899791, 4294899809, 4294899971, 4294900001, 4294900007, 4294900013, 4294900307, 4294900331, 4294900427, 4294900469, 4294900481, 4294900541, 4294900583, - 4294900781, 4294900853, 4294900931, 4294900991, 4294901033, 4294901087, 4294901159, 4294901267, 4294901393, 4294901411, 4294901489, 4294901657, 4294902011, 4294902071, 4294902101, 4294902107, 4294902353, 4294902377, 4294902599, 4294902647, 4294902743, 4294902869, 4294902977, 4294903067, 4294903103, 4294903259, 4294903289, 4294903397, 4294903421, 4294903493, 4294903577, 4294903631, 4294903637, 4294903733, 4294903799, 4294903823, 4294904003, 4294904033, 4294904081, 4294904129, 4294904279, 4294904297, 4294904303, 4294904333, 4294904351, 4294904381, - 4294904453, 4294904519, 4294904561, 4294904639, 4294904657, 4294904747, 4294904807, 4294904843, 4294905089, 4294905149, 4294905293, 4294905299, 4294905311, 4294905443, 4294905479, 4294905539, 4294905623, 4294905641, 4294905671, 4294905707, 4294905887, 4294905977, 4294906091, 4294906103, 4294906139, 4294906157, 4294906223, 4294906259, 4294906487, 4294906493, 4294906523, 4294906547, 4294906553, 4294906571, 4294906577, 4294906589, 4294906703, 4294906733, 4294906763, 4294906841, 4294906859, 4294906937, 4294907057, 4294907063, 4294907141, 4294907231, - 4294907249, 4294907261, 4294907267, 4294907387, 4294907417, 4294907567, 4294907603, 4294907699, 4294907789, 4294907849, 4294907873, 4294907879, 4294908023, 4294908071, 4294908119, 4294908209, 4294908227, 4294908329, 4294908491, 4294908503, 4294908569, 4294908653, 4294908713, 4294908719, 4294908791, 4294908839, 4294908869, 4294908989, 4294909031, 4294909067, 4294909109, 4294909253, 4294909529, 4294909589, 4294909643, 4294909739, 4294909799, 4294909811, 4294909853, 4294910003, 4294910039, 4294910189, 4294910201, 4294910219, 4294910273, 4294910333, - 4294910369, 4294910393, 4294910471, 4294910549, 4294910651, 4294910669, 4294910681, 4294910711, 4294910753, 4294910801, 4294910981, 4294911053, 4294911143, 4294911227, 4294911239, 4294911359, 4294911383, 4294911407, 4294911521, 4294911551, 4294911611, 4294911641, 4294911689, 4294911719, 4294911869, 4294912109, 4294912133, 4294912151, 4294912187, 4294912223, 4294912331, 4294912439, 4294912607, 4294912703, 4294912859, 4294912871, 4294912907, 4294912961, 4294913003, 4294913111, 4294913309, 4294913333, 4294913357, 4294913399, 4294913411, 4294913459, - 4294913501, 4294913531, 4294913591, 4294913609, 4294913663, 4294913783, 4294913819, 4294913903, 4294914137, 4294914413, 4294914473, 4294914497, 4294914527, 4294914551, 4294914593, 4294914611, 4294914659, 4294914671, 4294914743, 4294914863, 4294914917, 4294915061, 4294915103, 4294915139, 4294915217, 4294915223, 4294915253, 4294915283, 4294915373, 4294915433, 4294915607, 4294916069, 4294916213, 4294916267, 4294916303, 4294916393, 4294916441, 4294916477, 4294916507, 4294916573, 4294916633, 4294916687, 4294916783, 4294916837, 4294916897, 4294916921, - 4294917029, 4294917047, 4294917101, 4294917203, 4294917287, 4294917299, 4294917389, 4294917437, 4294917527, 4294917557, 4294917611, 4294917617, 4294917689, 4294917821, 4294917857, 4294917917, 4294917941, 4294918169, 4294918187, 4294918307, 4294918409, 4294918433, 4294918481, 4294918703, 4294918709, 4294918733, 4294918799, 4294918871, 4294919009, 4294919249, 4294919279, 4294919291, 4294919363, 4294919381, 4294919441, 4294919447, 4294919549, 4294919579, 4294919633, 4294919657, 4294919669, 4294919693, 4294919711, 4294920029, 4294920059, 4294920089, - 4294920197, 4294920239, 4294920257, 4294920263, 4294920269, 4294920341, 4294920353, 4294920407, 4294920503, 4294920599, 4294920647, 4294920743, 4294920803, 4294920809, 4294920881, 4294920899, 4294920983, 4294921043, 4294921139, 4294921151, 4294921181, 4294921229, 4294921289, 4294921331, 4294921343, 4294921391, 4294921469, 4294921709, 4294921721, 4294921823, 4294921847, 4294921889, 4294922057, 4294922171, 4294922201, 4294922237, 4294922309, 4294922399, 4294922447, 4294922507, 4294922513, 4294922549, 4294922609, 4294922663, 4294922861, 4294922933, - 4294923101, 4294923191, 4294923209, 4294923221, 4294923251, 4294923263, 4294923359, 4294923371, 4294923377, 4294923461, 4294923521, 4294923953, 4294924001, 4294924091, 4294924121, 4294924319, 4294924397, 4294924571, 4294924583, 4294924751, 4294924817, 4294924823, 4294924847, 4294924877, 4294925003, 4294925027, 4294925117, 4294925237, 4294925243, 4294925297, 4294925369, 4294925627, 4294925639, 4294925729, 4294925747, 4294925873, 4294925891, 4294925933, 4294926047, 4294926059, 4294926209, 4294926221, 4294926233, 4294926257, 4294926329, 4294926371, - 4294926401, 4294926413, 4294926437, 4294926563, 4294926569, 4294926917, 4294926923, 4294926947, 4294926971, 4294927067, 4294927073, 4294927151, 4294927349, 4294927367, 4294927403, 4294927481, 4294927523, 4294927553, 4294927589, 4294927649, 4294927673, 4294927727, 4294927739, 4294927763, 4294927889, 4294928183, 4294928207, 4294928249, 4294928327, 4294928351, 4294928399, 4294928483, 4294928489, 4294928543, 4294928597, 4294928951, 4294928963, 4294928981, 4294929017, 4294929059, 4294929161, 4294929197, 4294929233, 4294929269, 4294929311, 4294929323, - 4294929341, 4294929383, 4294929401, 4294929497, 4294929509, 4294929581, 4294929707, 4294929743, 4294930043, 4294930121, 4294930193, 4294930223, 4294930349, 4294930403, 4294930571, 4294930613, 4294930721, 4294930751, 4294930877, 4294930931, 4294930961, 4294930967, 4294930973, 4294931021, 4294931051, 4294931057, 4294931063, 4294931219, 4294931273, 4294931339, 4294931423, 4294931441, 4294931453, 4294931567, 4294931639, 4294931717, 4294931897, 4294931969, 4294932023, 4294932053, 4294932239, 4294932299, 4294932443, 4294932671, 4294932677, 4294932731, - 4294932743, 4294932767, 4294932773, 4294932779, 4294932881, 4294932899, 4294932929, 4294933067, 4294933277, 4294933307, 4294933343, 4294933451, 4294933523, 4294933763, 4294933793, 4294933829, 4294933847, 4294933871, 4294933997, 4294934033, 4294934111, 4294934207, 4294934243, 4294934267, 4294934279, 4294934291, 4294934327, 4294934363, 4294934423, 4294934489, 4294934561, 4294934867, 4294934921, 4294934969, 4294935137, 4294935239, 4294935299, 4294935431, 4294935539, 4294935629, 4294935701, 4294935791, 4294935797, 4294935803, 4294935959, 4294936001, - 4294936007, 4294936037, 4294936079, 4294936127, 4294936163, 4294936247, 4294936307, 4294936331, 4294936409, 4294936451, 4294936601, 4294936607, 4294936619, 4294936667, 4294936709, 4294936733, 4294936751, 4294936763, 4294936829, 4294936937, 4294936997, 4294937027, 4294937051, 4294937093, 4294937177, 4294937213, 4294937291, 4294937381, 4294937417, 4294937429, 4294937681, 4294937693, 4294937753, 4294937771, 4294937813, 4294937837, 4294937891, 4294937969, 4294938071, 4294938101, 4294938323, 4294938371, 4294938401, 4294938467, 4294938473, 4294938521, - 4294938599, 4294938731, 4294938779, 4294938833, 4294938899, 4294938977, 4294938983, 4294939067, 4294939127, 4294939223, 4294939277, 4294939331, 4294939337, 4294939391, 4294939457, 4294939559, 4294939673, 4294939691, 4294939901, 4294939991, 4294940087, 4294940093, 4294940189, 4294940213, 4294940417, 4294940657, 4294940699, 4294940753, 4294940801, 4294940873, 4294940951, 4294941047, 4294941143, 4294941161, 4294941227, 4294941281, 4294941377, 4294941509, 4294941551, 4294941701, 4294941731, 4294941767, 4294941911, 4294941923, 4294942043, 4294942139, - 4294942313, 4294942343, 4294942373, 4294942427, 4294942529, 4294942601, 4294942649, 4294942673, 4294942679, 4294942733, 4294942769, 4294942811, 4294942961, 4294943129, 4294943141, 4294943219, 4294943369, 4294943423, 4294943471, 4294943651, 4294943687, 4294943717, 4294943729, 4294943747, 4294943759, 4294943813, 4294943819, 4294943891, 4294944077, 4294944191, 4294944233, 4294944239, 4294944353, 4294944389, 4294944581, 4294944623, 4294944629, 4294944659, 4294944821, 4294945031, 4294945157, 4294945211, 4294945229, 4294945301, 4294945337, 4294945343, - 4294945511, 4294945547, 4294945667, 4294945709, 4294945757, 4294945841, 4294945991, 4294946033, 4294946099, 4294946153, 4294946477, 4294946687, 4294946747, 4294946957, 4294946993, 4294947023, 4294947131, 4294947167, 4294947287, 4294947311, 4294947413, 4294947581, 4294947599, 4294947671, 4294947851, 4294947959, 4294948067, 4294948073, 4294948193, 4294948259, 4294948421, 4294948451, 4294948613, 4294948673, 4294948883, 4294949027, 4294949057, 4294949069, 4294949519, 4294949531, 4294949603, 4294949609, 4294949627, 4294949693, 4294949729, 4294949741, - 4294949807, 4294949921, 4294949939, 4294949981, 4294949993, 4294950083, 4294950173, 4294950197, 4294950251, 4294950287, 4294950317, 4294950323, 4294950329, 4294950581, 4294950593, 4294950617, 4294950629, 4294950713, 4294950929, 4294951151, 4294951163, 4294951169, 4294951379, 4294951583, 4294951613, 4294951853, 4294951907, 4294951913, 4294951937, 4294951961, 4294952063, 4294952183, 4294952393, 4294952543, 4294952549, 4294952597, 4294952627, 4294952687, 4294952723, 4294952729, 4294952789, 4294952819, 4294952873, 4294952891, 4294952903, 4294952969, - 4294952999, 4294953023, 4294953107, 4294953173, 4294953281, 4294953341, 4294953431, 4294953599, 4294953689, 4294953719, 4294953827, 4294953887, 4294953977, 4294954073, 4294954079, 4294954157, 4294954217, 4294954283, 4294954607, 4294954667, 4294954859, 4294954901, 4294954973, 4294955081, 4294955237, 4294955273, 4294955327, 4294955441, 4294955507, 4294955591, 4294955789, 4294955831, 4294955837, 4294955927, 4294955963, 4294955969, 4294955987, 4294956041, 4294956047, 4294956197, 4294956323, 4294956359, 4294956551, 4294956593, 4294956623, 4294956629, - 4294956641, 4294956719, 4294956761, 4294956767, 4294956797, 4294956821, 4294956833, 4294957037, 4294957079, 4294957103, 4294957181, 4294957349, 4294957379, 4294957433, 4294957463, 4294957511, 4294957577, 4294957727, 4294957859, 4294957877, 4294958039, 4294958153, 4294958309, 4294958417, 4294958441, 4294958693, 4294958717, 4294958753, 4294958903, 4294958909, 4294959017, 4294959071, 4294959107, 4294959161, 4294959257, 4294959299, 4294959329, 4294959431, 4294959593, 4294959599, 4294959659, 4294959893, 4294959917, 4294959983, 4294960001, 4294960031, - 4294960061, 4294960079, 4294960097, 4294960271, 4294960283, 4294960349, 4294960367, 4294960421, 4294960529, 4294960541, 4294960583, 4294960613, 4294960673, 4294960691, 4294960697, 4294960787, 4294960919, 4294961003, 4294961039, 4294961153, 4294961159, 4294961171, 4294961321, 4294961411, 4294961471, 4294961507, 4294961537, 4294961669, 4294961717, 4294961741, 4294961873, 4294962059, 4294962137, 4294962167, 4294962263, 4294962281, 4294962311, 4294962341, 4294962413, 4294962521, 4294962563, 4294962761, 4294962893, 4294963103, 4294963163, 4294963223, - 4294963313, 4294963349, 4294963427, 4294963547, 4294963559, 4294963721, 4294963799, 4294963817, 4294963901, 4294963919, 4294964021, 4294964279, 4294964297, 4294964363, 4294964387, 4294964411, 4294964567, 4294964603, 4294964687, 4294964777, 4294965041, 4294965071, 4294965119, 4294965221, 4294965251, 4294965287, 4294965413, 4294965569, 4294965647, 4294965671, 4294965689, 4294965779, 4294965839, 4294965893, 4294966091, 4294966109, 4294966127, 4294966157, 4294966187, 4294966199, 4294966211, 4294966403, 4294966457, 4294966499, 4294966541, 4294966637, - 4294966661, 4294966739, 4294966823, 4294966883, 4294966901, 4294966961, 4294967027, 4294967087, 4294967099, 4294967123, 4294967153, 4294967249}; +const uint32_t ZT_MIMC52_PRIMES[1024] = { + 4294895267, 4294895477, 4294895513, 4294895519, 4294895543, 4294895567, 4294895657, 4294895711, 4294895777, + 4294895861, 4294895909, 4294895921, 4294895969, 4294896011, 4294896149, 4294896227, 4294896401, 4294896473, + 4294896527, 4294896563, 4294896653, 4294896731, 4294896863, 4294896899, 4294896983, 4294897037, 4294897103, + 4294897331, 4294897349, 4294897451, 4294897571, 4294897661, 4294897703, 4294897757, 4294897793, 4294897811, + 4294897817, 4294897829, 4294897877, 4294897919, 4294897991, 4294898027, 4294898129, 4294898153, 4294898231, + 4294898273, 4294898279, 4294898291, 4294898363, 4294898369, 4294898417, 4294898423, 4294898453, 4294898489, + 4294898573, 4294898579, 4294898639, 4294898693, 4294898747, 4294898759, 4294898867, 4294898879, 4294898909, + 4294898921, 4294898933, 4294899011, 4294899041, 4294899047, 4294899203, 4294899221, 4294899227, 4294899287, + 4294899341, 4294899431, 4294899509, 4294899533, 4294899539, 4294899551, 4294899629, 4294899791, 4294899809, + 4294899971, 4294900001, 4294900007, 4294900013, 4294900307, 4294900331, 4294900427, 4294900469, 4294900481, + 4294900541, 4294900583, 4294900781, 4294900853, 4294900931, 4294900991, 4294901033, 4294901087, 4294901159, + 4294901267, 4294901393, 4294901411, 4294901489, 4294901657, 4294902011, 4294902071, 4294902101, 4294902107, + 4294902353, 4294902377, 4294902599, 4294902647, 4294902743, 4294902869, 4294902977, 4294903067, 4294903103, + 4294903259, 4294903289, 4294903397, 4294903421, 4294903493, 4294903577, 4294903631, 4294903637, 4294903733, + 4294903799, 4294903823, 4294904003, 4294904033, 4294904081, 4294904129, 4294904279, 4294904297, 4294904303, + 4294904333, 4294904351, 4294904381, 4294904453, 4294904519, 4294904561, 4294904639, 4294904657, 4294904747, + 4294904807, 4294904843, 4294905089, 4294905149, 4294905293, 4294905299, 4294905311, 4294905443, 4294905479, + 4294905539, 4294905623, 4294905641, 4294905671, 4294905707, 4294905887, 4294905977, 4294906091, 4294906103, + 4294906139, 4294906157, 4294906223, 4294906259, 4294906487, 4294906493, 4294906523, 4294906547, 4294906553, + 4294906571, 4294906577, 4294906589, 4294906703, 4294906733, 4294906763, 4294906841, 4294906859, 4294906937, + 4294907057, 4294907063, 4294907141, 4294907231, 4294907249, 4294907261, 4294907267, 4294907387, 4294907417, + 4294907567, 4294907603, 4294907699, 4294907789, 4294907849, 4294907873, 4294907879, 4294908023, 4294908071, + 4294908119, 4294908209, 4294908227, 4294908329, 4294908491, 4294908503, 4294908569, 4294908653, 4294908713, + 4294908719, 4294908791, 4294908839, 4294908869, 4294908989, 4294909031, 4294909067, 4294909109, 4294909253, + 4294909529, 4294909589, 4294909643, 4294909739, 4294909799, 4294909811, 4294909853, 4294910003, 4294910039, + 4294910189, 4294910201, 4294910219, 4294910273, 4294910333, 4294910369, 4294910393, 4294910471, 4294910549, + 4294910651, 4294910669, 4294910681, 4294910711, 4294910753, 4294910801, 4294910981, 4294911053, 4294911143, + 4294911227, 4294911239, 4294911359, 4294911383, 4294911407, 4294911521, 4294911551, 4294911611, 4294911641, + 4294911689, 4294911719, 4294911869, 4294912109, 4294912133, 4294912151, 4294912187, 4294912223, 4294912331, + 4294912439, 4294912607, 4294912703, 4294912859, 4294912871, 4294912907, 4294912961, 4294913003, 4294913111, + 4294913309, 4294913333, 4294913357, 4294913399, 4294913411, 4294913459, 4294913501, 4294913531, 4294913591, + 4294913609, 4294913663, 4294913783, 4294913819, 4294913903, 4294914137, 4294914413, 4294914473, 4294914497, + 4294914527, 4294914551, 4294914593, 4294914611, 4294914659, 4294914671, 4294914743, 4294914863, 4294914917, + 4294915061, 4294915103, 4294915139, 4294915217, 4294915223, 4294915253, 4294915283, 4294915373, 4294915433, + 4294915607, 4294916069, 4294916213, 4294916267, 4294916303, 4294916393, 4294916441, 4294916477, 4294916507, + 4294916573, 4294916633, 4294916687, 4294916783, 4294916837, 4294916897, 4294916921, 4294917029, 4294917047, + 4294917101, 4294917203, 4294917287, 4294917299, 4294917389, 4294917437, 4294917527, 4294917557, 4294917611, + 4294917617, 4294917689, 4294917821, 4294917857, 4294917917, 4294917941, 4294918169, 4294918187, 4294918307, + 4294918409, 4294918433, 4294918481, 4294918703, 4294918709, 4294918733, 4294918799, 4294918871, 4294919009, + 4294919249, 4294919279, 4294919291, 4294919363, 4294919381, 4294919441, 4294919447, 4294919549, 4294919579, + 4294919633, 4294919657, 4294919669, 4294919693, 4294919711, 4294920029, 4294920059, 4294920089, 4294920197, + 4294920239, 4294920257, 4294920263, 4294920269, 4294920341, 4294920353, 4294920407, 4294920503, 4294920599, + 4294920647, 4294920743, 4294920803, 4294920809, 4294920881, 4294920899, 4294920983, 4294921043, 4294921139, + 4294921151, 4294921181, 4294921229, 4294921289, 4294921331, 4294921343, 4294921391, 4294921469, 4294921709, + 4294921721, 4294921823, 4294921847, 4294921889, 4294922057, 4294922171, 4294922201, 4294922237, 4294922309, + 4294922399, 4294922447, 4294922507, 4294922513, 4294922549, 4294922609, 4294922663, 4294922861, 4294922933, + 4294923101, 4294923191, 4294923209, 4294923221, 4294923251, 4294923263, 4294923359, 4294923371, 4294923377, + 4294923461, 4294923521, 4294923953, 4294924001, 4294924091, 4294924121, 4294924319, 4294924397, 4294924571, + 4294924583, 4294924751, 4294924817, 4294924823, 4294924847, 4294924877, 4294925003, 4294925027, 4294925117, + 4294925237, 4294925243, 4294925297, 4294925369, 4294925627, 4294925639, 4294925729, 4294925747, 4294925873, + 4294925891, 4294925933, 4294926047, 4294926059, 4294926209, 4294926221, 4294926233, 4294926257, 4294926329, + 4294926371, 4294926401, 4294926413, 4294926437, 4294926563, 4294926569, 4294926917, 4294926923, 4294926947, + 4294926971, 4294927067, 4294927073, 4294927151, 4294927349, 4294927367, 4294927403, 4294927481, 4294927523, + 4294927553, 4294927589, 4294927649, 4294927673, 4294927727, 4294927739, 4294927763, 4294927889, 4294928183, + 4294928207, 4294928249, 4294928327, 4294928351, 4294928399, 4294928483, 4294928489, 4294928543, 4294928597, + 4294928951, 4294928963, 4294928981, 4294929017, 4294929059, 4294929161, 4294929197, 4294929233, 4294929269, + 4294929311, 4294929323, 4294929341, 4294929383, 4294929401, 4294929497, 4294929509, 4294929581, 4294929707, + 4294929743, 4294930043, 4294930121, 4294930193, 4294930223, 4294930349, 4294930403, 4294930571, 4294930613, + 4294930721, 4294930751, 4294930877, 4294930931, 4294930961, 4294930967, 4294930973, 4294931021, 4294931051, + 4294931057, 4294931063, 4294931219, 4294931273, 4294931339, 4294931423, 4294931441, 4294931453, 4294931567, + 4294931639, 4294931717, 4294931897, 4294931969, 4294932023, 4294932053, 4294932239, 4294932299, 4294932443, + 4294932671, 4294932677, 4294932731, 4294932743, 4294932767, 4294932773, 4294932779, 4294932881, 4294932899, + 4294932929, 4294933067, 4294933277, 4294933307, 4294933343, 4294933451, 4294933523, 4294933763, 4294933793, + 4294933829, 4294933847, 4294933871, 4294933997, 4294934033, 4294934111, 4294934207, 4294934243, 4294934267, + 4294934279, 4294934291, 4294934327, 4294934363, 4294934423, 4294934489, 4294934561, 4294934867, 4294934921, + 4294934969, 4294935137, 4294935239, 4294935299, 4294935431, 4294935539, 4294935629, 4294935701, 4294935791, + 4294935797, 4294935803, 4294935959, 4294936001, 4294936007, 4294936037, 4294936079, 4294936127, 4294936163, + 4294936247, 4294936307, 4294936331, 4294936409, 4294936451, 4294936601, 4294936607, 4294936619, 4294936667, + 4294936709, 4294936733, 4294936751, 4294936763, 4294936829, 4294936937, 4294936997, 4294937027, 4294937051, + 4294937093, 4294937177, 4294937213, 4294937291, 4294937381, 4294937417, 4294937429, 4294937681, 4294937693, + 4294937753, 4294937771, 4294937813, 4294937837, 4294937891, 4294937969, 4294938071, 4294938101, 4294938323, + 4294938371, 4294938401, 4294938467, 4294938473, 4294938521, 4294938599, 4294938731, 4294938779, 4294938833, + 4294938899, 4294938977, 4294938983, 4294939067, 4294939127, 4294939223, 4294939277, 4294939331, 4294939337, + 4294939391, 4294939457, 4294939559, 4294939673, 4294939691, 4294939901, 4294939991, 4294940087, 4294940093, + 4294940189, 4294940213, 4294940417, 4294940657, 4294940699, 4294940753, 4294940801, 4294940873, 4294940951, + 4294941047, 4294941143, 4294941161, 4294941227, 4294941281, 4294941377, 4294941509, 4294941551, 4294941701, + 4294941731, 4294941767, 4294941911, 4294941923, 4294942043, 4294942139, 4294942313, 4294942343, 4294942373, + 4294942427, 4294942529, 4294942601, 4294942649, 4294942673, 4294942679, 4294942733, 4294942769, 4294942811, + 4294942961, 4294943129, 4294943141, 4294943219, 4294943369, 4294943423, 4294943471, 4294943651, 4294943687, + 4294943717, 4294943729, 4294943747, 4294943759, 4294943813, 4294943819, 4294943891, 4294944077, 4294944191, + 4294944233, 4294944239, 4294944353, 4294944389, 4294944581, 4294944623, 4294944629, 4294944659, 4294944821, + 4294945031, 4294945157, 4294945211, 4294945229, 4294945301, 4294945337, 4294945343, 4294945511, 4294945547, + 4294945667, 4294945709, 4294945757, 4294945841, 4294945991, 4294946033, 4294946099, 4294946153, 4294946477, + 4294946687, 4294946747, 4294946957, 4294946993, 4294947023, 4294947131, 4294947167, 4294947287, 4294947311, + 4294947413, 4294947581, 4294947599, 4294947671, 4294947851, 4294947959, 4294948067, 4294948073, 4294948193, + 4294948259, 4294948421, 4294948451, 4294948613, 4294948673, 4294948883, 4294949027, 4294949057, 4294949069, + 4294949519, 4294949531, 4294949603, 4294949609, 4294949627, 4294949693, 4294949729, 4294949741, 4294949807, + 4294949921, 4294949939, 4294949981, 4294949993, 4294950083, 4294950173, 4294950197, 4294950251, 4294950287, + 4294950317, 4294950323, 4294950329, 4294950581, 4294950593, 4294950617, 4294950629, 4294950713, 4294950929, + 4294951151, 4294951163, 4294951169, 4294951379, 4294951583, 4294951613, 4294951853, 4294951907, 4294951913, + 4294951937, 4294951961, 4294952063, 4294952183, 4294952393, 4294952543, 4294952549, 4294952597, 4294952627, + 4294952687, 4294952723, 4294952729, 4294952789, 4294952819, 4294952873, 4294952891, 4294952903, 4294952969, + 4294952999, 4294953023, 4294953107, 4294953173, 4294953281, 4294953341, 4294953431, 4294953599, 4294953689, + 4294953719, 4294953827, 4294953887, 4294953977, 4294954073, 4294954079, 4294954157, 4294954217, 4294954283, + 4294954607, 4294954667, 4294954859, 4294954901, 4294954973, 4294955081, 4294955237, 4294955273, 4294955327, + 4294955441, 4294955507, 4294955591, 4294955789, 4294955831, 4294955837, 4294955927, 4294955963, 4294955969, + 4294955987, 4294956041, 4294956047, 4294956197, 4294956323, 4294956359, 4294956551, 4294956593, 4294956623, + 4294956629, 4294956641, 4294956719, 4294956761, 4294956767, 4294956797, 4294956821, 4294956833, 4294957037, + 4294957079, 4294957103, 4294957181, 4294957349, 4294957379, 4294957433, 4294957463, 4294957511, 4294957577, + 4294957727, 4294957859, 4294957877, 4294958039, 4294958153, 4294958309, 4294958417, 4294958441, 4294958693, + 4294958717, 4294958753, 4294958903, 4294958909, 4294959017, 4294959071, 4294959107, 4294959161, 4294959257, + 4294959299, 4294959329, 4294959431, 4294959593, 4294959599, 4294959659, 4294959893, 4294959917, 4294959983, + 4294960001, 4294960031, 4294960061, 4294960079, 4294960097, 4294960271, 4294960283, 4294960349, 4294960367, + 4294960421, 4294960529, 4294960541, 4294960583, 4294960613, 4294960673, 4294960691, 4294960697, 4294960787, + 4294960919, 4294961003, 4294961039, 4294961153, 4294961159, 4294961171, 4294961321, 4294961411, 4294961471, + 4294961507, 4294961537, 4294961669, 4294961717, 4294961741, 4294961873, 4294962059, 4294962137, 4294962167, + 4294962263, 4294962281, 4294962311, 4294962341, 4294962413, 4294962521, 4294962563, 4294962761, 4294962893, + 4294963103, 4294963163, 4294963223, 4294963313, 4294963349, 4294963427, 4294963547, 4294963559, 4294963721, + 4294963799, 4294963817, 4294963901, 4294963919, 4294964021, 4294964279, 4294964297, 4294964363, 4294964387, + 4294964411, 4294964567, 4294964603, 4294964687, 4294964777, 4294965041, 4294965071, 4294965119, 4294965221, + 4294965251, 4294965287, 4294965413, 4294965569, 4294965647, 4294965671, 4294965689, 4294965779, 4294965839, + 4294965893, 4294966091, 4294966109, 4294966127, 4294966157, 4294966187, 4294966199, 4294966211, 4294966403, + 4294966457, 4294966499, 4294966541, 4294966637, 4294966661, 4294966739, 4294966823, 4294966883, 4294966901, + 4294966961, 4294967027, 4294967087, 4294967099, 4294967123, 4294967153, 4294967249 +}; #ifdef ZT_NO_IEEE_DOUBLE @@ -49,14 +143,14 @@ const uint32_t ZT_MIMC52_PRIMES[1024] = {4294895267, 4294895477, 4294895513, 429 * much slower on systems that can use the FPU hack. */ static uint64_t mulmod64(uint64_t a, uint64_t b, const uint64_t m) { - uint64_t res = 0; - while ((a)) { - if ((a << 63U)) - res = (res + b) % m; - a >>= 1U; - b = (b << 1U) % m; - } - return res; + uint64_t res = 0; + while ((a)) { + if ((a << 63U)) + res = (res + b) % m; + a >>= 1U; + b = (b << 1U) % m; + } + return res; } #define mulmod52(a, b, m, mf) mulmod64((a), (b), (m)) @@ -69,10 +163,10 @@ static uint64_t mulmod64(uint64_t a, uint64_t b, const uint64_t m) * performs fairly equally across CPUs. */ ZT_INLINE uint64_t mulmod52(uint64_t a, const uint64_t b, const uint64_t m, const double mf) { - a = ( ( a * b ) - ( ((uint64_t)(((double)a * (double)b) / mf) - 1) * m ) ); - //a -= m * (uint64_t)(a > m); // faster on some systems, but slower on newer cores - a %= m; - return a; + a = ((a * b) - (((uint64_t)(((double)a * (double)b) / mf) - 1) * m)); + // a -= m * (uint64_t)(a > m); // faster on some systems, but slower on newer cores + a %= m; + return a; } #endif @@ -80,18 +174,19 @@ ZT_INLINE uint64_t mulmod52(uint64_t a, const uint64_t b, const uint64_t m, cons // Compute a^e%m (mf is m in floating point form to avoid repeated conversion) ZT_INLINE uint64_t modpow52(uint64_t a, uint64_t e, const uint64_t m, const double mf) { - uint64_t res = 1ULL; - for (;;) { - if ((e << 63U)) { - res = mulmod52(res, a, m, mf); - } - if (likely((e >>= 1U) != 0)) { - a = mulmod52(a, a, m, mf); - } else { - break; - } - } - return res; + uint64_t res = 1ULL; + for (;;) { + if ((e << 63U)) { + res = mulmod52(res, a, m, mf); + } + if (likely((e >>= 1U) != 0)) { + a = mulmod52(a, a, m, mf); + } + else { + break; + } + } + return res; } static const ZeroTier::AES s_mimc52AES("abcdefghijklmnopqrstuvwxyz012345"); @@ -100,60 +195,60 @@ static const ZeroTier::AES s_mimc52AES("abcdefghijklmnopqrstuvwxyz012345"); // This doesn't have to be non-reversible or secure, just strongly random. ZT_INLINE void fillK(uint64_t k[34], const uint8_t challenge[32]) { - s_mimc52AES.encrypt(challenge, k); - s_mimc52AES.encrypt(challenge + 16, k + 2); - k[2] ^= k[0]; - k[3] ^= k[1]; - for (unsigned int i = 2, j = 4; j < 34; i += 2, j += 2) - s_mimc52AES.encrypt(k + i, k + j); + s_mimc52AES.encrypt(challenge, k); + s_mimc52AES.encrypt(challenge + 16, k + 2); + k[2] ^= k[0]; + k[3] ^= k[1]; + for (unsigned int i = 2, j = 4; j < 34; i += 2, j += 2) + s_mimc52AES.encrypt(k + i, k + j); #if __BYTE_ORDER == __BIG_ENDIAN - for (unsigned int i = 0; i < 34; ++i) - k[i] = Utils::swapBytes(k[i]); + for (unsigned int i = 0; i < 34; ++i) + k[i] = Utils::swapBytes(k[i]); #endif } -} // anonymous namespace +} // anonymous namespace namespace ZeroTier { namespace MIMC52 { uint64_t delay(const uint8_t challenge[32], const unsigned long rounds) { - uint64_t k[34]; - fillK(k, challenge); + uint64_t k[34]; + fillK(k, challenge); - const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023]; - const uint64_t e = ((p * 2ULL) - 1ULL) / 3ULL; - const uint64_t m52 = 0xfffffffffffffULL; - const double pf = (double)p; + const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023]; + const uint64_t e = ((p * 2ULL) - 1ULL) / 3ULL; + const uint64_t m52 = 0xfffffffffffffULL; + const double pf = (double)p; - uint64_t x = k[33] % p; - for (unsigned long r = 0, kn = rounds; r < rounds; ++r) { - x = (x - k[--kn & 31]) & m52; - x = modpow52(x, e, p, pf); - } + uint64_t x = k[33] % p; + for (unsigned long r = 0, kn = rounds; r < rounds; ++r) { + x = (x - k[--kn & 31]) & m52; + x = modpow52(x, e, p, pf); + } - return x; + return x; } bool verify(const uint8_t challenge[32], const unsigned long rounds, uint64_t proof) { - uint64_t k[34]; - fillK(k, challenge); + uint64_t k[34]; + fillK(k, challenge); - const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023]; - const uint64_t m52 = 0xfffffffffffffULL; - const double pf = (double)p; + const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023]; + const uint64_t m52 = 0xfffffffffffffULL; + const double pf = (double)p; - for (unsigned long r = 0; r < rounds; ++r) { - const uint64_t kk = k[r & 31]; - proof = mulmod52(mulmod52(proof, proof, p, pf), proof, p, pf); // y = y ^ 3 - proof = (proof + kk) & m52; - } + for (unsigned long r = 0; r < rounds; ++r) { + const uint64_t kk = k[r & 31]; + proof = mulmod52(mulmod52(proof, proof, p, pf), proof, p, pf); // y = y ^ 3 + proof = (proof + kk) & m52; + } - return ((proof % p) == (k[33] % p)); + return ((proof % p) == (k[33] % p)); } -} // namespace MIMC52 -} // namespace ZeroTier +} // namespace MIMC52 +} // namespace ZeroTier diff --git a/core/MIMC52.hpp b/core/MIMC52.hpp index 4388493df..022df9300 100644 --- a/core/MIMC52.hpp +++ b/core/MIMC52.hpp @@ -56,7 +56,7 @@ uint64_t delay(const uint8_t challenge[32], unsigned long rounds); */ bool verify(const uint8_t challenge[32], unsigned long rounds, uint64_t proof); -} // namespace MIMC52 -} // namespcae ZeroTier +} // namespace MIMC52 +} // namespace ZeroTier #endif diff --git a/core/Member.cpp b/core/Member.cpp index b34c10170..223810ea5 100644 --- a/core/Member.cpp +++ b/core/Member.cpp @@ -11,27 +11,32 @@ */ /****/ -#include - #include "Member.hpp" + #include "Context.hpp" #include "Peer.hpp" #include "Topology.hpp" +#include + namespace ZeroTier { -Member::Member() : - m_comRevocationThreshold(0), - m_lastPushedCredentials(0), - m_comAgreementLocalTimestamp(0), - m_comAgreementRemoteTimestamp(0) +Member::Member() + : m_comRevocationThreshold(0) + , m_lastPushedCredentials(0) + , m_comAgreementLocalTimestamp(0) + , m_comAgreementRemoteTimestamp(0) { } -void Member::pushCredentials(const Context &ctx, const CallContext &cc, const SharedPtr< Peer > &to, const NetworkConfig &nconf) +void Member::pushCredentials( + const Context& ctx, + const CallContext& cc, + const SharedPtr& to, + const NetworkConfig& nconf) { - if (!nconf.com) // sanity check - return; + if (! nconf.com) // sanity check + return; #if 0 SharedPtr outp(new Buf()); @@ -112,147 +117,242 @@ void Member::pushCredentials(const Context &ctx, const CallContext &cc, const Sh } #endif - m_lastPushedCredentials = cc.ticks; + m_lastPushedCredentials = cc.ticks; } -void Member::clean(const NetworkConfig &nconf) +void Member::clean(const NetworkConfig& nconf) { - m_cleanCredImpl< TagCredential >(nconf, m_remoteTags); - m_cleanCredImpl< CapabilityCredential >(nconf, m_remoteCaps); - m_cleanCredImpl< OwnershipCredential >(nconf, m_remoteCoos); + m_cleanCredImpl(nconf, m_remoteTags); + m_cleanCredImpl(nconf, m_remoteCaps); + m_cleanCredImpl(nconf, m_remoteCoos); } Member::AddCredentialResult Member::addCredential( - const Context &ctx, - const CallContext &cc, - const Identity &sourcePeerIdentity, - const NetworkConfig &nconf, - const MembershipCredential &com) + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const MembershipCredential& com) { - const int64_t newts = com.timestamp(); - if (newts <= m_comRevocationThreshold) { - ctx.t->credentialRejected(cc, 0xd9992121, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); - return ADD_REJECTED; - } + const int64_t newts = com.timestamp(); + if (newts <= m_comRevocationThreshold) { + ctx.t->credentialRejected( + cc, + 0xd9992121, + com.networkId(), + sourcePeerIdentity, + com.id(), + com.timestamp(), + ZT_CREDENTIAL_TYPE_COM, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); + return ADD_REJECTED; + } - const int64_t oldts = m_com.timestamp(); - if (newts < oldts) { - ctx.t->credentialRejected(cc, 0xd9928192, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); - return ADD_REJECTED; - } - if ((newts == oldts) && (m_com == com)) - return ADD_ACCEPTED_REDUNDANT; + const int64_t oldts = m_com.timestamp(); + if (newts < oldts) { + ctx.t->credentialRejected( + cc, + 0xd9928192, + com.networkId(), + sourcePeerIdentity, + com.id(), + com.timestamp(), + ZT_CREDENTIAL_TYPE_COM, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); + return ADD_REJECTED; + } + if ((newts == oldts) && (m_com == com)) + return ADD_ACCEPTED_REDUNDANT; - switch (com.verify(ctx, cc)) { - default: - ctx.t->credentialRejected(cc, 0x0f198241, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return Member::ADD_REJECTED; - case Credential::VERIFY_OK: - m_com = com; - return ADD_ACCEPTED_NEW; - case Credential::VERIFY_BAD_SIGNATURE: - ctx.t->credentialRejected(cc, 0xbaf0aaaa, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED); - return ADD_REJECTED; - case Credential::VERIFY_NEED_IDENTITY: - return ADD_DEFERRED_FOR_WHOIS; - } + switch (com.verify(ctx, cc)) { + default: + ctx.t->credentialRejected( + cc, + 0x0f198241, + com.networkId(), + sourcePeerIdentity, + com.id(), + com.timestamp(), + ZT_CREDENTIAL_TYPE_COM, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); + return Member::ADD_REJECTED; + case Credential::VERIFY_OK: + m_com = com; + return ADD_ACCEPTED_NEW; + case Credential::VERIFY_BAD_SIGNATURE: + ctx.t->credentialRejected( + cc, + 0xbaf0aaaa, + com.networkId(), + sourcePeerIdentity, + com.id(), + com.timestamp(), + ZT_CREDENTIAL_TYPE_COM, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED); + return ADD_REJECTED; + case Credential::VERIFY_NEED_IDENTITY: + return ADD_DEFERRED_FOR_WHOIS; + } } // 3/5 of the credential types have identical addCredential() code -template< typename C > +template static ZT_INLINE Member::AddCredentialResult _addCredImpl( - Map< uint32_t, C > &remoteCreds, - const Map< uint64_t, int64_t > &revocations, - const Context &ctx, - const CallContext &cc, - const Identity &sourcePeerIdentity, - const NetworkConfig &nconf, - const C &cred) + Map& remoteCreds, + const Map& revocations, + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const C& cred) { - typename Map< uint32_t, C >::const_iterator rc(remoteCreds.find(cred.id())); - if (rc != remoteCreds.end()) { - if (rc->second.revision() > cred.revision()) { - ctx.t->credentialRejected(cc, 0x40000001, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); - return Member::ADD_REJECTED; - } - if (rc->second == cred) - return Member::ADD_ACCEPTED_REDUNDANT; - } + typename Map::const_iterator rc(remoteCreds.find(cred.id())); + if (rc != remoteCreds.end()) { + if (rc->second.revision() > cred.revision()) { + ctx.t->credentialRejected( + cc, + 0x40000001, + nconf.networkId, + sourcePeerIdentity, + cred.id(), + cred.revision(), + C::credentialType(), + ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); + return Member::ADD_REJECTED; + } + if (rc->second == cred) + return Member::ADD_ACCEPTED_REDUNDANT; + } - typename Map< uint64_t, int64_t >::const_iterator rt(revocations.find(Member::credentialKey(C::credentialType(), cred.id()))); - if ((rt != revocations.end()) && (rt->second >= cred.revision())) { - ctx.t->credentialRejected(cc, 0x24248124, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); - return Member::ADD_REJECTED; - } + typename Map::const_iterator rt( + revocations.find(Member::credentialKey(C::credentialType(), cred.id()))); + if ((rt != revocations.end()) && (rt->second >= cred.revision())) { + ctx.t->credentialRejected( + cc, + 0x24248124, + nconf.networkId, + sourcePeerIdentity, + cred.id(), + cred.revision(), + C::credentialType(), + ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); + return Member::ADD_REJECTED; + } - switch (cred.verify(ctx, cc)) { - default: - ctx.t->credentialRejected(cc, 0x01feba012, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return Member::ADD_REJECTED; - case 0: - if (rc == remoteCreds.end()) - remoteCreds[cred.id()] = cred; - return Member::ADD_ACCEPTED_NEW; - case 1: - return Member::ADD_DEFERRED_FOR_WHOIS; - } + switch (cred.verify(ctx, cc)) { + default: + ctx.t->credentialRejected( + cc, + 0x01feba012, + nconf.networkId, + sourcePeerIdentity, + cred.id(), + cred.revision(), + C::credentialType(), + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); + return Member::ADD_REJECTED; + case 0: + if (rc == remoteCreds.end()) + remoteCreds[cred.id()] = cred; + return Member::ADD_ACCEPTED_NEW; + case 1: + return Member::ADD_DEFERRED_FOR_WHOIS; + } } -Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const TagCredential &tag) -{ return _addCredImpl< TagCredential >(m_remoteTags, m_revocations, ctx, cc, sourcePeerIdentity, nconf, tag); } - -Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const CapabilityCredential &cap) -{ return _addCredImpl< CapabilityCredential >(m_remoteCaps, m_revocations, ctx, cc, sourcePeerIdentity, nconf, cap); } - -Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const OwnershipCredential &coo) -{ return _addCredImpl< OwnershipCredential >(m_remoteCoos, m_revocations, ctx, cc, sourcePeerIdentity, nconf, coo); } - -Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const RevocationCredential &rev) +Member::AddCredentialResult Member::addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const TagCredential& tag) { - int64_t *rt; - switch (rev.verify(ctx, cc)) { - default: - ctx.t->credentialRejected(cc, 0x938ff009, nconf.networkId, sourcePeerIdentity, rev.id(), 0, ZT_CREDENTIAL_TYPE_REVOCATION, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return ADD_REJECTED; - case 0: { - const ZT_CredentialType ct = rev.typeBeingRevoked(); - switch (ct) { - case ZT_CREDENTIAL_TYPE_COM: - if (rev.threshold() > m_comRevocationThreshold) { - m_comRevocationThreshold = rev.threshold(); - return ADD_ACCEPTED_NEW; - } - return ADD_ACCEPTED_REDUNDANT; - case ZT_CREDENTIAL_TYPE_CAPABILITY: - case ZT_CREDENTIAL_TYPE_TAG: - case ZT_CREDENTIAL_TYPE_COO: - rt = &(m_revocations[credentialKey(ct, rev.credentialId())]); - if (*rt < rev.threshold()) { - *rt = rev.threshold(); - m_comRevocationThreshold = rev.threshold(); - return ADD_ACCEPTED_NEW; - } - return ADD_ACCEPTED_REDUNDANT; - default: - ctx.t->credentialRejected(cc, 0x0bbbb1a4, nconf.networkId, sourcePeerIdentity, rev.id(), 0, ZT_CREDENTIAL_TYPE_REVOCATION, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return ADD_REJECTED; - } - } - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } + return _addCredImpl(m_remoteTags, m_revocations, ctx, cc, sourcePeerIdentity, nconf, tag); } -bool Member::m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept +Member::AddCredentialResult Member::addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const CapabilityCredential& cap) { - return ( - ip.isV6() && - nconf.ndpEmulation() && - ( - (ip == InetAddress::makeIpv66plane(nconf.networkId, m_com.issuedTo().address)) || - (ip == InetAddress::makeIpv6rfc4193(nconf.networkId, m_com.issuedTo().address)) - ) - ); + return _addCredImpl(m_remoteCaps, m_revocations, ctx, cc, sourcePeerIdentity, nconf, cap); } -} // namespace ZeroTier +Member::AddCredentialResult Member::addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const OwnershipCredential& coo) +{ + return _addCredImpl(m_remoteCoos, m_revocations, ctx, cc, sourcePeerIdentity, nconf, coo); +} + +Member::AddCredentialResult Member::addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const RevocationCredential& rev) +{ + int64_t* rt; + switch (rev.verify(ctx, cc)) { + default: + ctx.t->credentialRejected( + cc, + 0x938ff009, + nconf.networkId, + sourcePeerIdentity, + rev.id(), + 0, + ZT_CREDENTIAL_TYPE_REVOCATION, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); + return ADD_REJECTED; + case 0: { + const ZT_CredentialType ct = rev.typeBeingRevoked(); + switch (ct) { + case ZT_CREDENTIAL_TYPE_COM: + if (rev.threshold() > m_comRevocationThreshold) { + m_comRevocationThreshold = rev.threshold(); + return ADD_ACCEPTED_NEW; + } + return ADD_ACCEPTED_REDUNDANT; + case ZT_CREDENTIAL_TYPE_CAPABILITY: + case ZT_CREDENTIAL_TYPE_TAG: + case ZT_CREDENTIAL_TYPE_COO: + rt = &(m_revocations[credentialKey(ct, rev.credentialId())]); + if (*rt < rev.threshold()) { + *rt = rev.threshold(); + m_comRevocationThreshold = rev.threshold(); + return ADD_ACCEPTED_NEW; + } + return ADD_ACCEPTED_REDUNDANT; + default: + ctx.t->credentialRejected( + cc, + 0x0bbbb1a4, + nconf.networkId, + sourcePeerIdentity, + rev.id(), + 0, + ZT_CREDENTIAL_TYPE_REVOCATION, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); + return ADD_REJECTED; + } + } + case 1: + return ADD_DEFERRED_FOR_WHOIS; + } +} + +bool Member::m_isUnspoofableAddress(const NetworkConfig& nconf, const InetAddress& ip) const noexcept +{ + return ( + ip.isV6() && nconf.ndpEmulation() + && ((ip == InetAddress::makeIpv66plane(nconf.networkId, m_com.issuedTo().address)) + || (ip == InetAddress::makeIpv6rfc4193(nconf.networkId, m_com.issuedTo().address)))); +} + +} // namespace ZeroTier diff --git a/core/Member.hpp b/core/Member.hpp index 984d54f13..5931d0419 100644 --- a/core/Member.hpp +++ b/core/Member.hpp @@ -14,14 +14,14 @@ #ifndef ZT_MEMBERSHIP_HPP #define ZT_MEMBERSHIP_HPP -#include "Constants.hpp" -#include "Credential.hpp" -#include "Containers.hpp" -#include "MembershipCredential.hpp" #include "CapabilityCredential.hpp" -#include "TagCredential.hpp" -#include "RevocationCredential.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Credential.hpp" +#include "MembershipCredential.hpp" #include "NetworkConfig.hpp" +#include "RevocationCredential.hpp" +#include "TagCredential.hpp" namespace ZeroTier { @@ -36,200 +36,230 @@ class Network; * * This class is not thread safe. It must be locked externally. */ -class Member -{ -public: - enum AddCredentialResult - { - ADD_REJECTED, - ADD_ACCEPTED_NEW, - ADD_ACCEPTED_REDUNDANT, - ADD_DEFERRED_FOR_WHOIS - }; +class Member { + public: + enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS }; - Member(); + Member(); - /** - * Send COM and other credentials to this peer - * - * @param to Peer identity - * @param nconf My network config - */ - void pushCredentials(const Context &ctx, const CallContext &cc, const SharedPtr< Peer > &to, const NetworkConfig &nconf); + /** + * Send COM and other credentials to this peer + * + * @param to Peer identity + * @param nconf My network config + */ + void + pushCredentials(const Context& ctx, const CallContext& cc, const SharedPtr& to, const NetworkConfig& nconf); - /** - * @return Time we last pushed credentials to this member - */ - ZT_INLINE int64_t lastPushedCredentials() const noexcept - { return m_lastPushedCredentials; } + /** + * @return Time we last pushed credentials to this member + */ + ZT_INLINE int64_t lastPushedCredentials() const noexcept + { + return m_lastPushedCredentials; + } - /** - * Get a remote member's tag (if we have it) - * - * @param nconf Network configuration - * @param id Tag ID - * @return Pointer to tag or NULL if not found - */ - ZT_INLINE const TagCredential *getTag(const NetworkConfig &nconf, const uint32_t id) const noexcept - { - Map< uint32_t, TagCredential >::const_iterator t(m_remoteTags.find(id)); - return (((t != m_remoteTags.end()) && (m_isCredentialTimestampValid(nconf, t->second))) ? &(t->second) : (TagCredential *)0); - } + /** + * Get a remote member's tag (if we have it) + * + * @param nconf Network configuration + * @param id Tag ID + * @return Pointer to tag or NULL if not found + */ + ZT_INLINE const TagCredential* getTag(const NetworkConfig& nconf, const uint32_t id) const noexcept + { + Map::const_iterator t(m_remoteTags.find(id)); + return ( + ((t != m_remoteTags.end()) && (m_isCredentialTimestampValid(nconf, t->second))) ? &(t->second) + : (TagCredential*)0); + } - /** - * Clean internal databases of stale entries - * - * @param nconf Current network configuration - */ - void clean(const NetworkConfig &nconf); + /** + * Clean internal databases of stale entries + * + * @param nconf Current network configuration + */ + void clean(const NetworkConfig& nconf); - /** - * Generates a key for internal use in indexing credentials by type and credential ID - */ - static ZT_INLINE uint64_t credentialKey(const ZT_CredentialType &t, const uint32_t i) noexcept - { return (((uint64_t)t << 32U) | (uint64_t)i); } + /** + * Generates a key for internal use in indexing credentials by type and credential ID + */ + static ZT_INLINE uint64_t credentialKey(const ZT_CredentialType& t, const uint32_t i) noexcept + { + return (((uint64_t)t << 32U) | (uint64_t)i); + } - /** - * Check whether the peer represented by this Membership owns a given address - * - * @tparam Type of resource: InetAddress or MAC - * @param nconf Our network config - * @param r Resource to check - * @return True if this peer has a certificate of ownership for the given resource - */ - template< typename T > - ZT_INLINE bool peerOwnsAddress(const NetworkConfig &nconf, const T &r) const noexcept - { - if (m_isUnspoofableAddress(nconf, r)) - return true; - for (Map< uint32_t, OwnershipCredential >::const_iterator i(m_remoteCoos.begin()); i != m_remoteCoos.end(); ++i) { - if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r))) - return true; - } - return false; - } + /** + * Check whether the peer represented by this Membership owns a given address + * + * @tparam Type of resource: InetAddress or MAC + * @param nconf Our network config + * @param r Resource to check + * @return True if this peer has a certificate of ownership for the given resource + */ + template ZT_INLINE bool peerOwnsAddress(const NetworkConfig& nconf, const T& r) const noexcept + { + if (m_isUnspoofableAddress(nconf, r)) + return true; + for (Map::const_iterator i(m_remoteCoos.begin()); i != m_remoteCoos.end(); ++i) { + if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r))) + return true; + } + return false; + } - /** - * Check if our local COM agrees with theirs, with possible memo-ization. - * - * @param localCom - */ - ZT_INLINE bool certificateOfMembershipAgress(const MembershipCredential &localCom, const Identity &remoteIdentity) - { - if ((m_comAgreementLocalTimestamp == localCom.timestamp()) && (m_comAgreementRemoteTimestamp == m_com.timestamp())) - return true; - if (m_com.agreesWith(localCom)) { - // SECURITY: newer network controllers embed the full fingerprint into the COM. If we are - // joined to a network managed by one of these, our COM will contain one. If it's present - // we compare vs the other and require them to match. If our COM does not contain a full - // identity fingerprint we compare by address only, which is a legacy mode supported for - // old network controllers. Note that this is safe because the controller issues us our COM - // and in so doing indicates if it's new or old. However this will go away after a while - // once we can be pretty sure there are no ancient controllers around. - if (localCom.issuedTo().haveHash()) { - if (localCom.issuedTo() != m_com.issuedTo()) - return false; - } else { - // LEGACY: support networks run by old controllers. - if (localCom.issuedTo().address != m_com.issuedTo().address) - return false; - } + /** + * Check if our local COM agrees with theirs, with possible memo-ization. + * + * @param localCom + */ + ZT_INLINE bool certificateOfMembershipAgress(const MembershipCredential& localCom, const Identity& remoteIdentity) + { + if ((m_comAgreementLocalTimestamp == localCom.timestamp()) + && (m_comAgreementRemoteTimestamp == m_com.timestamp())) + return true; + if (m_com.agreesWith(localCom)) { + // SECURITY: newer network controllers embed the full fingerprint into the COM. If we are + // joined to a network managed by one of these, our COM will contain one. If it's present + // we compare vs the other and require them to match. If our COM does not contain a full + // identity fingerprint we compare by address only, which is a legacy mode supported for + // old network controllers. Note that this is safe because the controller issues us our COM + // and in so doing indicates if it's new or old. However this will go away after a while + // once we can be pretty sure there are no ancient controllers around. + if (localCom.issuedTo().haveHash()) { + if (localCom.issuedTo() != m_com.issuedTo()) + return false; + } + else { + // LEGACY: support networks run by old controllers. + if (localCom.issuedTo().address != m_com.issuedTo().address) + return false; + } - // Remember that these two COMs agreed. If any are updated this is invalidated and a full - // agreement check will be done again. - m_comAgreementLocalTimestamp = localCom.timestamp(); - m_comAgreementRemoteTimestamp = m_com.timestamp(); + // Remember that these two COMs agreed. If any are updated this is invalidated and a full + // agreement check will be done again. + m_comAgreementLocalTimestamp = localCom.timestamp(); + m_comAgreementRemoteTimestamp = m_com.timestamp(); - return true; - } - return false; - } + return true; + } + return false; + } - AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const MembershipCredential &com); - AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const TagCredential &tag); - AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const CapabilityCredential &cap); - AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const OwnershipCredential &coo); - AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const RevocationCredential &rev); + AddCredentialResult addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const MembershipCredential& com); + AddCredentialResult addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const TagCredential& tag); + AddCredentialResult addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const CapabilityCredential& cap); + AddCredentialResult addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const OwnershipCredential& coo); + AddCredentialResult addCredential( + const Context& ctx, + const CallContext& cc, + const Identity& sourcePeerIdentity, + const NetworkConfig& nconf, + const RevocationCredential& rev); -private: - // This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT - // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to - // always return true for them. A certificate is not required for these. - ZT_INLINE bool m_isUnspoofableAddress(const NetworkConfig &nconf, const MAC &m) const noexcept - { return false; } + private: + // This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT + // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to + // always return true for them. A certificate is not required for these. + ZT_INLINE bool m_isUnspoofableAddress(const NetworkConfig& nconf, const MAC& m) const noexcept + { + return false; + } - bool m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept; + bool m_isUnspoofableAddress(const NetworkConfig& nconf, const InetAddress& ip) const noexcept; - // This compares the remote credential's timestamp to the timestamp in our network config - // plus or minus the permitted maximum timestamp delta. - template< typename C > - ZT_INLINE bool m_isCredentialTimestampValid(const NetworkConfig &nconf, const C &remoteCredential) const noexcept - { - const int64_t ts = remoteCredential.revision(); - if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { - Map< uint64_t, int64_t >::const_iterator threshold(m_revocations.find(credentialKey(C::credentialType(), remoteCredential.id()))); - return ((threshold == m_revocations.end()) || (ts > threshold->second)); - } - return false; - } + // This compares the remote credential's timestamp to the timestamp in our network config + // plus or minus the permitted maximum timestamp delta. + template + ZT_INLINE bool m_isCredentialTimestampValid(const NetworkConfig& nconf, const C& remoteCredential) const noexcept + { + const int64_t ts = remoteCredential.revision(); + if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) + <= nconf.credentialTimeMaxDelta) { + Map::const_iterator threshold( + m_revocations.find(credentialKey(C::credentialType(), remoteCredential.id()))); + return ((threshold == m_revocations.end()) || (ts > threshold->second)); + } + return false; + } - template< typename C > - ZT_INLINE void m_cleanCredImpl(const NetworkConfig &nconf, Map< uint32_t, C > &remoteCreds) - { - for (typename Map< uint32_t, C >::iterator i(remoteCreds.begin()); i != remoteCreds.end();) { - if (!m_isCredentialTimestampValid(nconf, i->second)) - remoteCreds.erase(i++); - else ++i; - } - } + template ZT_INLINE void m_cleanCredImpl(const NetworkConfig& nconf, Map& remoteCreds) + { + for (typename Map::iterator i(remoteCreds.begin()); i != remoteCreds.end();) { + if (! m_isCredentialTimestampValid(nconf, i->second)) + remoteCreds.erase(i++); + else + ++i; + } + } - // Revocation threshold for COM or 0 if none - int64_t m_comRevocationThreshold; + // Revocation threshold for COM or 0 if none + int64_t m_comRevocationThreshold; - // Time we last pushed credentials - int64_t m_lastPushedCredentials; + // Time we last pushed credentials + int64_t m_lastPushedCredentials; - // COM timestamps at which we last agreed-- used to memo-ize agreement and avoid having to recompute constantly. - int64_t m_comAgreementLocalTimestamp, m_comAgreementRemoteTimestamp; + // COM timestamps at which we last agreed-- used to memo-ize agreement and avoid having to recompute constantly. + int64_t m_comAgreementLocalTimestamp, m_comAgreementRemoteTimestamp; - // Remote member's latest network COM - MembershipCredential m_com; + // Remote member's latest network COM + MembershipCredential m_com; - // Revocations by credentialKey() - Map< uint64_t, int64_t > m_revocations; + // Revocations by credentialKey() + Map m_revocations; - // Remote credentials that we have received from this member (and that are valid) - Map< uint32_t, TagCredential > m_remoteTags; - Map< uint32_t, CapabilityCredential > m_remoteCaps; - Map< uint32_t, OwnershipCredential > m_remoteCoos; + // Remote credentials that we have received from this member (and that are valid) + Map m_remoteTags; + Map m_remoteCaps; + Map m_remoteCoos; -public: - class CapabilityIterator - { - public: - ZT_INLINE CapabilityIterator(Member &m, const NetworkConfig &nconf) noexcept: - m_hti(m.m_remoteCaps.begin()), - m_parent(m), - m_nconf(nconf) - {} + public: + class CapabilityIterator { + public: + ZT_INLINE CapabilityIterator(Member& m, const NetworkConfig& nconf) noexcept + : m_hti(m.m_remoteCaps.begin()) + , m_parent(m) + , m_nconf(nconf) + { + } - ZT_INLINE CapabilityCredential *next() noexcept - { - while (m_hti != m_parent.m_remoteCaps.end()) { - Map< uint32_t, CapabilityCredential >::iterator i(m_hti++); - if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second)) - return &(i->second); - } - return nullptr; - } + ZT_INLINE CapabilityCredential* next() noexcept + { + while (m_hti != m_parent.m_remoteCaps.end()) { + Map::iterator i(m_hti++); + if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second)) + return &(i->second); + } + return nullptr; + } - private: - Map< uint32_t, CapabilityCredential >::iterator m_hti; - Member &m_parent; - const NetworkConfig &m_nconf; - }; + private: + Map::iterator m_hti; + Member& m_parent; + const NetworkConfig& m_nconf; + }; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/MembershipCredential.cpp b/core/MembershipCredential.cpp index c4ae26da9..8e8099b10 100644 --- a/core/MembershipCredential.cpp +++ b/core/MembershipCredential.cpp @@ -15,275 +15,304 @@ namespace ZeroTier { -MembershipCredential::MembershipCredential(const int64_t timestamp, const int64_t timestampMaxDelta, const uint64_t nwid, const Identity &issuedTo) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) - m_timestamp(timestamp), - m_timestampMaxDelta(timestampMaxDelta), - m_networkId(nwid), - m_issuedTo(issuedTo.fingerprint()), - m_signatureLength(0) -{} - -bool MembershipCredential::agreesWith(const MembershipCredential &other) const noexcept +MembershipCredential::MembershipCredential( + const int64_t timestamp, + const int64_t timestampMaxDelta, + const uint64_t nwid, + const Identity& issuedTo) noexcept + : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + m_timestamp(timestamp) + , m_timestampMaxDelta(timestampMaxDelta) + , m_networkId(nwid) + , m_issuedTo(issuedTo.fingerprint()) + , m_signatureLength(0) { - // NOTE: we always do explicit absolute value with an if() since llabs() can have overflow - // conditions that could introduce a vulnerability. - - if (other.m_timestamp > m_timestamp) { - if ((other.m_timestamp - m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) - return false; - } else { - if ((m_timestamp - other.m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) - return false; - } - - // us <> them - for (FCV::const_iterator i(m_additionalQualifiers.begin()); i != m_additionalQualifiers.end(); ++i) { - if (i->delta != 0xffffffffffffffffULL) { - const uint64_t *v2 = nullptr; - for (FCV::const_iterator j(other.m_additionalQualifiers.begin()); j != other.m_additionalQualifiers.end(); ++i) { - if (j->id == i->id) { - v2 = &(j->value); - break; - } - } - if (!v2) - return false; - if (*v2 > i->value) { - if ((*v2 - i->value) > i->delta) - return false; - } else { - if ((i->value - *v2) > i->delta) - return false; - } - } - } - - // them <> us (we need a second pass in case they have qualifiers we don't or vice versa) - for (FCV::const_iterator i(other.m_additionalQualifiers.begin()); i != other.m_additionalQualifiers.end(); ++i) { - if (i->delta != 0xffffffffffffffffULL) { - const uint64_t *v2 = nullptr; - for (FCV::const_iterator j(m_additionalQualifiers.begin()); j != m_additionalQualifiers.end(); ++i) { - if (j->id == i->id) { - v2 = &(j->value); - break; - } - } - if (!v2) - return false; - if (*v2 > i->value) { - if ((*v2 - i->value) > i->delta) - return false; - } else { - if ((i->value - *v2) > i->delta) - return false; - } - } - } - - // SECURITY: check for issued-to inequality is a sanity check. This should be impossible since elsewhere - // in the code COMs are checked to ensure that they do in fact belong to their issued-to identities. - return (other.m_networkId == m_networkId) && (m_networkId != 0) && (other.m_issuedTo.address != m_issuedTo.address); } -bool MembershipCredential::sign(const Identity &with) noexcept +bool MembershipCredential::agreesWith(const MembershipCredential& other) const noexcept { - m_signedBy = with.address(); - uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; - const unsigned int bufSize = m_fillSigningBuf(buf); - m_signatureLength = with.sign(buf, bufSize, m_signature, sizeof(m_signature)); - return m_signatureLength > 0; + // NOTE: we always do explicit absolute value with an if() since llabs() can have overflow + // conditions that could introduce a vulnerability. + + if (other.m_timestamp > m_timestamp) { + if ((other.m_timestamp - m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) + return false; + } + else { + if ((m_timestamp - other.m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) + return false; + } + + // us <> them + for (FCV::const_iterator i( + m_additionalQualifiers.begin()); + i != m_additionalQualifiers.end(); + ++i) { + if (i->delta != 0xffffffffffffffffULL) { + const uint64_t* v2 = nullptr; + for (FCV::const_iterator j( + other.m_additionalQualifiers.begin()); + j != other.m_additionalQualifiers.end(); + ++i) { + if (j->id == i->id) { + v2 = &(j->value); + break; + } + } + if (! v2) + return false; + if (*v2 > i->value) { + if ((*v2 - i->value) > i->delta) + return false; + } + else { + if ((i->value - *v2) > i->delta) + return false; + } + } + } + + // them <> us (we need a second pass in case they have qualifiers we don't or vice versa) + for (FCV::const_iterator i( + other.m_additionalQualifiers.begin()); + i != other.m_additionalQualifiers.end(); + ++i) { + if (i->delta != 0xffffffffffffffffULL) { + const uint64_t* v2 = nullptr; + for (FCV::const_iterator j( + m_additionalQualifiers.begin()); + j != m_additionalQualifiers.end(); + ++i) { + if (j->id == i->id) { + v2 = &(j->value); + break; + } + } + if (! v2) + return false; + if (*v2 > i->value) { + if ((*v2 - i->value) > i->delta) + return false; + } + else { + if ((i->value - *v2) > i->delta) + return false; + } + } + } + + // SECURITY: check for issued-to inequality is a sanity check. This should be impossible since elsewhere + // in the code COMs are checked to ensure that they do in fact belong to their issued-to identities. + return (other.m_networkId == m_networkId) && (m_networkId != 0) && (other.m_issuedTo.address != m_issuedTo.address); +} + +bool MembershipCredential::sign(const Identity& with) noexcept +{ + m_signedBy = with.address(); + uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; + const unsigned int bufSize = m_fillSigningBuf(buf); + m_signatureLength = with.sign(buf, bufSize, m_signature, sizeof(m_signature)); + return m_signatureLength > 0; } int MembershipCredential::marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], const bool v2) const noexcept { - data[0] = v2 ? 2 : 1; + data[0] = v2 ? 2 : 1; - // All formats start with the standard three qualifiers: timestamp with delta, network ID as a strict - // equality compare, and the address of the issued-to node as an informational tuple. - int p = 3; - Utils::storeBigEndian(data + p, 0); - Utils::storeBigEndian(data + p + 8, (uint64_t) m_timestamp); - Utils::storeBigEndian(data + p + 16, (uint64_t) m_timestampMaxDelta); - Utils::storeBigEndian(data + p + 24, 1); - Utils::storeBigEndian(data + p + 32, m_networkId); - Utils::storeBigEndian(data + p + 40, 0); - Utils::storeBigEndian(data + p + 48, 2); - Utils::storeBigEndian(data + p + 56, m_issuedTo.address); - Utils::storeMachineEndian< uint64_t >(data + p + 64, 0xffffffffffffffffULL); - p += 72; + // All formats start with the standard three qualifiers: timestamp with delta, network ID as a strict + // equality compare, and the address of the issued-to node as an informational tuple. + int p = 3; + Utils::storeBigEndian(data + p, 0); + Utils::storeBigEndian(data + p + 8, (uint64_t)m_timestamp); + Utils::storeBigEndian(data + p + 16, (uint64_t)m_timestampMaxDelta); + Utils::storeBigEndian(data + p + 24, 1); + Utils::storeBigEndian(data + p + 32, m_networkId); + Utils::storeBigEndian(data + p + 40, 0); + Utils::storeBigEndian(data + p + 48, 2); + Utils::storeBigEndian(data + p + 56, m_issuedTo.address); + Utils::storeMachineEndian(data + p + 64, 0xffffffffffffffffULL); + p += 72; - if (v2) { - // V2 marshal format will have three tuples followed by the fingerprint hash. - Utils::storeBigEndian(data + 1, 3); - Utils::copy(data + p, m_issuedTo.hash); - p += 48; - } else { - // V1 marshal format must shove everything into tuples, resulting in nine. - Utils::storeBigEndian(data + 1, 9); - for (int k = 0;k < 6;++k) { - Utils::storeBigEndian(data + p, (uint64_t) k + 3); - Utils::storeMachineEndian< uint64_t >(data + p + 8, Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + (k * 8))); - Utils::storeMachineEndian< uint64_t >(data + p + 16, 0xffffffffffffffffULL); - p += 24; - } - } + if (v2) { + // V2 marshal format will have three tuples followed by the fingerprint hash. + Utils::storeBigEndian(data + 1, 3); + Utils::copy(data + p, m_issuedTo.hash); + p += 48; + } + else { + // V1 marshal format must shove everything into tuples, resulting in nine. + Utils::storeBigEndian(data + 1, 9); + for (int k = 0; k < 6; ++k) { + Utils::storeBigEndian(data + p, (uint64_t)k + 3); + Utils::storeMachineEndian( + data + p + 8, + Utils::loadMachineEndian(m_issuedTo.hash + (k * 8))); + Utils::storeMachineEndian(data + p + 16, 0xffffffffffffffffULL); + p += 24; + } + } - m_signedBy.copyTo(data + p); - p += 5; + m_signedBy.copyTo(data + p); + p += 5; - if (v2) { - // V2 marshal format prefixes signatures with a 16-bit length to support future signature types. - Utils::storeBigEndian(data + p, (uint16_t) m_signatureLength); - p += 2; - Utils::copy(data + p, m_signature, m_signatureLength); - p += (int)m_signatureLength; - } else { - // V1 only supports 96-byte signature fields. - Utils::copy<96>(data + p, m_signature); - p += 96; - } + if (v2) { + // V2 marshal format prefixes signatures with a 16-bit length to support future signature types. + Utils::storeBigEndian(data + p, (uint16_t)m_signatureLength); + p += 2; + Utils::copy(data + p, m_signature, m_signatureLength); + p += (int)m_signatureLength; + } + else { + // V1 only supports 96-byte signature fields. + Utils::copy<96>(data + p, m_signature); + p += 96; + } - return p; + return p; } -int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept +int MembershipCredential::unmarshal(const uint8_t* data, int len) noexcept { - if (len < (1 + 2 + 72)) - return -1; + if (len < (1 + 2 + 72)) + return -1; - TriviallyCopyable::memoryZero(this); + TriviallyCopyable::memoryZero(this); - const unsigned int numq = Utils::loadBigEndian(data + 1); - if ((numq < 3) || (numq > (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS + 3))) - return -1; - int p = 3; - for (unsigned int q = 0;q < numq;++q) { - if ((p + 24) > len) - return -1; - const uint64_t id = Utils::loadBigEndian(data + p); - p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) - const uint64_t value = Utils::loadBigEndian(data + p); - p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) - const uint64_t delta = Utils::loadBigEndian(data + p); - p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) - switch (id) { - case 0: - m_timestamp = (int64_t) value; - m_timestampMaxDelta = (int64_t) delta; - break; - case 1: - m_networkId = value; - break; - case 2: - m_issuedTo.address = value; - break; + const unsigned int numq = Utils::loadBigEndian(data + 1); + if ((numq < 3) || (numq > (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS + 3))) + return -1; + int p = 3; + for (unsigned int q = 0; q < numq; ++q) { + if ((p + 24) > len) + return -1; + const uint64_t id = Utils::loadBigEndian(data + p); + p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) + const uint64_t value = Utils::loadBigEndian(data + p); + p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) + const uint64_t delta = Utils::loadBigEndian(data + p); + p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) + switch (id) { + case 0: + m_timestamp = (int64_t)value; + m_timestampMaxDelta = (int64_t)delta; + break; + case 1: + m_networkId = value; + break; + case 2: + m_issuedTo.address = value; + break; - // V1 nodes will pack the hash into qualifier tuples. - case 3: - Utils::storeBigEndian(m_issuedTo.hash, value); - break; - case 4: - Utils::storeBigEndian(m_issuedTo.hash + 8, value); - break; - case 5: - Utils::storeBigEndian(m_issuedTo.hash + 16, value); - break; - case 6: - Utils::storeBigEndian(m_issuedTo.hash + 24, value); - break; - case 7: - Utils::storeBigEndian(m_issuedTo.hash + 32, value); - break; - case 8: - Utils::storeBigEndian(m_issuedTo.hash + 40, value); - break; + // V1 nodes will pack the hash into qualifier tuples. + case 3: + Utils::storeBigEndian(m_issuedTo.hash, value); + break; + case 4: + Utils::storeBigEndian(m_issuedTo.hash + 8, value); + break; + case 5: + Utils::storeBigEndian(m_issuedTo.hash + 16, value); + break; + case 6: + Utils::storeBigEndian(m_issuedTo.hash + 24, value); + break; + case 7: + Utils::storeBigEndian(m_issuedTo.hash + 32, value); + break; + case 8: + Utils::storeBigEndian(m_issuedTo.hash + 40, value); + break; - default: - if (m_additionalQualifiers.size() >= ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS) - return -1; - m_additionalQualifiers.push_back(p_Qualifier(id, value, delta)); - break; - } - } + default: + if (m_additionalQualifiers.size() >= ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS) + return -1; + m_additionalQualifiers.push_back(p_Qualifier(id, value, delta)); + break; + } + } - std::sort(m_additionalQualifiers.begin(), m_additionalQualifiers.end()); + std::sort(m_additionalQualifiers.begin(), m_additionalQualifiers.end()); - if (data[0] == 1) { - if ((p + 96) > len) - return -1; - m_signatureLength = 96; - Utils::copy<96>(m_signature, data + p); - return p + 96; - } else if (data[0] == 2) { - if ((p + 48) > len) - return -1; - Utils::copy<48>(m_issuedTo.hash, data + p); - p += 48; - if ((p + 2) > len) - return -1; - m_signatureLength = Utils::loadBigEndian(data + p); - if ((m_signatureLength > (unsigned int) sizeof(m_signature)) || ((p + (int) m_signatureLength) > len)) - return -1; - Utils::copy(m_signature, data + p, m_signatureLength); - return p + (int) m_signatureLength; - } + if (data[0] == 1) { + if ((p + 96) > len) + return -1; + m_signatureLength = 96; + Utils::copy<96>(m_signature, data + p); + return p + 96; + } + else if (data[0] == 2) { + if ((p + 48) > len) + return -1; + Utils::copy<48>(m_issuedTo.hash, data + p); + p += 48; + if ((p + 2) > len) + return -1; + m_signatureLength = Utils::loadBigEndian(data + p); + if ((m_signatureLength > (unsigned int)sizeof(m_signature)) || ((p + (int)m_signatureLength) > len)) + return -1; + Utils::copy(m_signature, data + p, m_signatureLength); + return p + (int)m_signatureLength; + } - return -1; + return -1; } -unsigned int MembershipCredential::m_fillSigningBuf(uint64_t *buf) const noexcept +unsigned int MembershipCredential::m_fillSigningBuf(uint64_t* buf) const noexcept { - const uint64_t informational = 0xffffffffffffffffULL; + const uint64_t informational = 0xffffffffffffffffULL; - /* - * Signing always embeds all data to be signed in qualifier tuple format for - * backward compatibility with V1 nodes, since otherwise we'd need a signature - * for v1 nodes to verify and another for v2 nodes to verify. - */ + /* + * Signing always embeds all data to be signed in qualifier tuple format for + * backward compatibility with V1 nodes, since otherwise we'd need a signature + * for v1 nodes to verify and another for v2 nodes to verify. + */ - // The standard three tuples that must begin every COM. - buf[0] = 0; - buf[1] = Utils::hton((uint64_t) m_timestamp); - buf[2] = Utils::hton((uint64_t) m_timestampMaxDelta); - buf[3] = ZT_CONST_TO_BE_UINT64(1); - buf[4] = Utils::hton(m_networkId); - buf[5] = 0; - buf[6] = ZT_CONST_TO_BE_UINT64(2); - buf[7] = Utils::hton(m_issuedTo.address); - buf[8] = informational; + // The standard three tuples that must begin every COM. + buf[0] = 0; + buf[1] = Utils::hton((uint64_t)m_timestamp); + buf[2] = Utils::hton((uint64_t)m_timestampMaxDelta); + buf[3] = ZT_CONST_TO_BE_UINT64(1); + buf[4] = Utils::hton(m_networkId); + buf[5] = 0; + buf[6] = ZT_CONST_TO_BE_UINT64(2); + buf[7] = Utils::hton(m_issuedTo.address); + buf[8] = informational; - unsigned int p = 9; + unsigned int p = 9; - // The full identity fingerprint of the peer to whom the COM was issued, - // embeded as a series of informational tuples. - if (m_issuedTo.haveHash()) { - buf[p++] = ZT_CONST_TO_BE_UINT64(3); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash); - buf[p++] = informational; - buf[p++] = ZT_CONST_TO_BE_UINT64(4); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 8); - buf[p++] = informational; - buf[p++] = ZT_CONST_TO_BE_UINT64(5); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 16); - buf[p++] = informational; - buf[p++] = ZT_CONST_TO_BE_UINT64(6); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 24); - buf[p++] = informational; - buf[p++] = ZT_CONST_TO_BE_UINT64(7); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 32); - buf[p++] = informational; - buf[p++] = ZT_CONST_TO_BE_UINT64(8); - buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 40); - buf[p++] = informational; - } + // The full identity fingerprint of the peer to whom the COM was issued, + // embeded as a series of informational tuples. + if (m_issuedTo.haveHash()) { + buf[p++] = ZT_CONST_TO_BE_UINT64(3); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash); + buf[p++] = informational; + buf[p++] = ZT_CONST_TO_BE_UINT64(4); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash + 8); + buf[p++] = informational; + buf[p++] = ZT_CONST_TO_BE_UINT64(5); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash + 16); + buf[p++] = informational; + buf[p++] = ZT_CONST_TO_BE_UINT64(6); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash + 24); + buf[p++] = informational; + buf[p++] = ZT_CONST_TO_BE_UINT64(7); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash + 32); + buf[p++] = informational; + buf[p++] = ZT_CONST_TO_BE_UINT64(8); + buf[p++] = Utils::loadMachineEndian(m_issuedTo.hash + 40); + buf[p++] = informational; + } - for (FCV::const_iterator i(m_additionalQualifiers.begin()); i != m_additionalQualifiers.end(); ++i) { // NOLINT(modernize-loop-convert) - buf[p++] = Utils::hton(i->id); - buf[p++] = Utils::hton(i->value); - buf[p++] = Utils::hton(i->delta); - } + for (FCV::const_iterator i( + m_additionalQualifiers.begin()); + i != m_additionalQualifiers.end(); + ++i) { // NOLINT(modernize-loop-convert) + buf[p++] = Utils::hton(i->id); + buf[p++] = Utils::hton(i->value); + buf[p++] = Utils::hton(i->delta); + } - return p * 8; + return p * 8; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/MembershipCredential.hpp b/core/MembershipCredential.hpp index a7a919cb8..4c8c6dc48 100644 --- a/core/MembershipCredential.hpp +++ b/core/MembershipCredential.hpp @@ -14,23 +14,24 @@ #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP -#include -#include -#include - -#include "Constants.hpp" -#include "Credential.hpp" #include "Address.hpp" #include "C25519.hpp" +#include "Constants.hpp" +#include "Credential.hpp" +#include "FCV.hpp" #include "Identity.hpp" #include "Utils.hpp" -#include "FCV.hpp" + +#include +#include +#include // Maximum number of additional tuples beyond the standard always-present three. #define ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS 8 // version + qualifier count + three required qualifiers + additional qualifiers + -#define ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX (1 + 2 + (3 * 3 * 8) + (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS * 3 * 8) + 144 + 5 + 2 + 96) +#define ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX \ + (1 + 2 + (3 * 3 * 8) + (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS * 3 * 8) + 144 + 5 + 2 + 96) namespace ZeroTier { @@ -96,135 +97,166 @@ class Context; * order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is * then signed. */ -class MembershipCredential : public Credential -{ - friend class Credential; +class MembershipCredential : public Credential { + friend class Credential; -public: - static constexpr ZT_CredentialType credentialType() noexcept - { return ZT_CREDENTIAL_TYPE_COM; } + public: + static constexpr ZT_CredentialType credentialType() noexcept + { + return ZT_CREDENTIAL_TYPE_COM; + } - /** - * Create an empty certificate of membership - */ - ZT_INLINE MembershipCredential() noexcept - { memoryZero(this); } + /** + * Create an empty certificate of membership + */ + ZT_INLINE MembershipCredential() noexcept + { + memoryZero(this); + } - /** - * Create from required fields common to all networks - * - * @param timestamp Timestamp of certificate - * @param timestampMaxDelta Maximum variation between timestamps on this net - * @param nwid Network ID - * @param issuedTo Certificate recipient - */ - MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity &issuedTo) noexcept; + /** + * Create from required fields common to all networks + * + * @param timestamp Timestamp of certificate + * @param timestampMaxDelta Maximum variation between timestamps on this net + * @param nwid Network ID + * @param issuedTo Certificate recipient + */ + MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo) + noexcept; - /** - * @return True if there's something here - */ - ZT_INLINE operator bool() const noexcept - { return (m_networkId != 0); } + /** + * @return True if there's something here + */ + ZT_INLINE operator bool() const noexcept + { + return (m_networkId != 0); + } - /** - * @return Credential ID, always 0 for COMs - */ - ZT_INLINE uint32_t id() const noexcept - { return 0; } + /** + * @return Credential ID, always 0 for COMs + */ + ZT_INLINE uint32_t id() const noexcept + { + return 0; + } - /** - * @return Timestamp for this cert and maximum delta for timestamp - */ - ZT_INLINE int64_t timestamp() const noexcept - { return m_timestamp; } + /** + * @return Timestamp for this cert and maximum delta for timestamp + */ + ZT_INLINE int64_t timestamp() const noexcept + { + return m_timestamp; + } - ZT_INLINE int64_t revision() const noexcept - { return m_timestamp; } + ZT_INLINE int64_t revision() const noexcept + { + return m_timestamp; + } - /** - * @return Maximum allowed difference between timestamps - */ - ZT_INLINE int64_t timestampMaxDelta() const noexcept - { return m_timestampMaxDelta; } + /** + * @return Maximum allowed difference between timestamps + */ + ZT_INLINE int64_t timestampMaxDelta() const noexcept + { + return m_timestampMaxDelta; + } - /** - * @return Fingerprint of identity to which this cert was issued - */ - ZT_INLINE const Fingerprint &issuedTo() const noexcept - { return m_issuedTo; } + /** + * @return Fingerprint of identity to which this cert was issued + */ + ZT_INLINE const Fingerprint& issuedTo() const noexcept + { + return m_issuedTo; + } - /** - * @return Network ID for which this cert was issued - */ - ZT_INLINE uint64_t networkId() const noexcept - { return m_networkId; } + /** + * @return Network ID for which this cert was issued + */ + ZT_INLINE uint64_t networkId() const noexcept + { + return m_networkId; + } - /** - * Compare two certificates for parameter agreement - * - * This compares this certificate with the other and returns true if all - * parameters in this cert are present in the other and if they agree to - * within this cert's max delta value for each given parameter. - * - * Tuples present in other but not in this cert are ignored, but any - * tuples present in this cert but not in other result in 'false'. - * - * @param other Cert to compare with - * @return True if certs agree and 'other' may be communicated with - */ - bool agreesWith(const MembershipCredential &other) const noexcept; + /** + * Compare two certificates for parameter agreement + * + * This compares this certificate with the other and returns true if all + * parameters in this cert are present in the other and if they agree to + * within this cert's max delta value for each given parameter. + * + * Tuples present in other but not in this cert are ignored, but any + * tuples present in this cert but not in other result in 'false'. + * + * @param other Cert to compare with + * @return True if certs agree and 'other' may be communicated with + */ + bool agreesWith(const MembershipCredential& other) const noexcept; - /** - * Sign this certificate - * - * @param with Identity to sign with, must include private key - * @return True if signature was successful - */ - bool sign(const Identity &with) noexcept; + /** + * Sign this certificate + * + * @param with Identity to sign with, must include private key + * @return True if signature was successful + */ + bool sign(const Identity& with) noexcept; - /** - * Verify this COM and its signature - * - * @param RR Runtime environment for looking up peers - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const - { return s_verify(ctx, cc, *this); } + /** + * Verify this COM and its signature + * + * @param RR Runtime environment for looking up peers + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const + { + return s_verify(ctx, cc, *this); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], bool v2 = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], bool v2 = false) const noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; -private: - unsigned int m_fillSigningBuf(uint64_t *buf) const noexcept; + private: + unsigned int m_fillSigningBuf(uint64_t* buf) const noexcept; - struct p_Qualifier - { - ZT_INLINE p_Qualifier() noexcept: id(0), value(0), delta(0) - {} + struct p_Qualifier { + ZT_INLINE p_Qualifier() noexcept + : id(0) + , value(0) + , delta(0) + { + } - ZT_INLINE p_Qualifier(const uint64_t id_, const uint64_t value_, const uint64_t delta_) noexcept: id(id_), value(value_), delta(delta_) - {} + ZT_INLINE p_Qualifier(const uint64_t id_, const uint64_t value_, const uint64_t delta_) noexcept + : id(id_) + , value(value_) + , delta(delta_) + { + } - uint64_t id; - uint64_t value; - uint64_t delta; - ZT_INLINE bool operator<(const p_Qualifier &q) const noexcept - { return (id < q.id); } // sort order - }; + uint64_t id; + uint64_t value; + uint64_t delta; + ZT_INLINE bool operator<(const p_Qualifier& q) const noexcept + { + return (id < q.id); + } // sort order + }; - FCV< p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS > m_additionalQualifiers; - int64_t m_timestamp; - int64_t m_timestampMaxDelta; - uint64_t m_networkId; - Fingerprint m_issuedTo; - Address m_signedBy; - unsigned int m_signatureLength; - uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; + FCV m_additionalQualifiers; + int64_t m_timestamp; + int64_t m_timestampMaxDelta; + uint64_t m_networkId; + Fingerprint m_issuedTo; + Address m_signedBy; + unsigned int m_signatureLength; + uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Meter.hpp b/core/Meter.hpp index e597d3d84..1e445ca77 100644 --- a/core/Meter.hpp +++ b/core/Meter.hpp @@ -34,59 +34,61 @@ namespace ZeroTier { * @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second) * @tparam LSIZE Log size in units of time (default: 10 for 10s worth of data) */ -template -class Meter -{ -public: - /** - * Create and initialize a new meter - * - * @param now Start time - */ - ZT_INLINE Meter() noexcept - {} +template class Meter { + public: + /** + * Create and initialize a new meter + * + * @param now Start time + */ + ZT_INLINE Meter() noexcept + { + } - /** - * Add a measurement - * - * @param ts Timestamp for measurement - * @param count Count of items (usually bytes) - */ - ZT_INLINE void log(const int64_t ts, const uint64_t count) noexcept - { - // We log by choosing a log bucket based on the current time in units modulo - // the log size and then if it's a new bucket setting it or otherwise adding - // to it. - const unsigned long bucket = ((unsigned long)(ts / TUNIT)) % LSIZE; - if (unlikely(m_bucket.exchange(bucket, std::memory_order_relaxed) != bucket)) { - m_totalExclCounts.fetch_add(m_counts[bucket].exchange(count, std::memory_order_relaxed), std::memory_order_relaxed); - } else { - m_counts[bucket].fetch_add(count, std::memory_order_relaxed); - } - } + /** + * Add a measurement + * + * @param ts Timestamp for measurement + * @param count Count of items (usually bytes) + */ + ZT_INLINE void log(const int64_t ts, const uint64_t count) noexcept + { + // We log by choosing a log bucket based on the current time in units modulo + // the log size and then if it's a new bucket setting it or otherwise adding + // to it. + const unsigned long bucket = ((unsigned long)(ts / TUNIT)) % LSIZE; + if (unlikely(m_bucket.exchange(bucket, std::memory_order_relaxed) != bucket)) { + m_totalExclCounts.fetch_add( + m_counts[bucket].exchange(count, std::memory_order_relaxed), + std::memory_order_relaxed); + } + else { + m_counts[bucket].fetch_add(count, std::memory_order_relaxed); + } + } - /** - * Get rate per TUNIT time - * - * @param now Current time - * @param rate Result parameter: rate in count/TUNIT - * @param total Total count for life of object - */ - ZT_INLINE void rate(double &rate, uint64_t &total) const noexcept - { - total = 0; - for (unsigned long i = 0;i < LSIZE;++i) - total += m_counts[i].load(std::memory_order_relaxed); - rate = (double) total / (double) LSIZE; - total += m_totalExclCounts.load(std::memory_order_relaxed); - } + /** + * Get rate per TUNIT time + * + * @param now Current time + * @param rate Result parameter: rate in count/TUNIT + * @param total Total count for life of object + */ + ZT_INLINE void rate(double& rate, uint64_t& total) const noexcept + { + total = 0; + for (unsigned long i = 0; i < LSIZE; ++i) + total += m_counts[i].load(std::memory_order_relaxed); + rate = (double)total / (double)LSIZE; + total += m_totalExclCounts.load(std::memory_order_relaxed); + } -private: - std::atomic m_counts[LSIZE]; - std::atomic m_totalExclCounts; - std::atomic m_bucket; + private: + std::atomic m_counts[LSIZE]; + std::atomic m_totalExclCounts; + std::atomic m_bucket; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/MulticastGroup.hpp b/core/MulticastGroup.hpp index fca0a58c0..912e3861a 100644 --- a/core/MulticastGroup.hpp +++ b/core/MulticastGroup.hpp @@ -15,10 +15,10 @@ #define ZT_MULTICASTGROUP_HPP #include "Constants.hpp" -#include "MAC.hpp" #include "InetAddress.hpp" -#include "Utils.hpp" +#include "MAC.hpp" #include "TriviallyCopyable.hpp" +#include "Utils.hpp" namespace ZeroTier { @@ -37,84 +37,108 @@ namespace ZeroTier { * * MulticastGroup behaves as an immutable value object. */ -class MulticastGroup : public TriviallyCopyable -{ -public: - ZT_INLINE MulticastGroup() noexcept: m_mac(), m_adi(0) - {} +class MulticastGroup : public TriviallyCopyable { + public: + ZT_INLINE MulticastGroup() noexcept + : m_mac() + , m_adi(0) + { + } - ZT_INLINE MulticastGroup(const MAC &m, uint32_t a) noexcept: m_mac(m), m_adi(a) - {} + ZT_INLINE MulticastGroup(const MAC& m, uint32_t a) noexcept + : m_mac(m) + , m_adi(a) + { + } - /** - * Derive the multicast group used for address resolution (ARP/NDP) for an IP - * - * @param ip IP address (port field is ignored) - * @return Multicast group for ARP/NDP - */ - static ZT_INLINE MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) noexcept - { - if (ip.isV4()) { - // IPv4 wants broadcast MACs, so we shove the V4 address itself into - // the Multicast Group ADI field. Making V4 ARP work is basically why - // ADI was added, as well as handling other things that want mindless - // Ethernet broadcast to all. - return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); - } else if (ip.isV6()) { - // IPv6 is better designed in this respect. We can compute the IPv6 - // multicast address directly from the IP address, and it gives us - // 24 bits of uniqueness. Collisions aren't likely to be common enough - // to care about. - const uint8_t *const a = reinterpret_cast(ip.rawIpData()); // NOLINT(hicpp-use-auto,modernize-use-auto) - return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0); - } - return MulticastGroup(); // NOLINT(modernize-return-braced-init-list) - } + /** + * Derive the multicast group used for address resolution (ARP/NDP) for an IP + * + * @param ip IP address (port field is ignored) + * @return Multicast group for ARP/NDP + */ + static ZT_INLINE MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip) noexcept + { + if (ip.isV4()) { + // IPv4 wants broadcast MACs, so we shove the V4 address itself into + // the Multicast Group ADI field. Making V4 ARP work is basically why + // ADI was added, as well as handling other things that want mindless + // Ethernet broadcast to all. + return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData()))); + } + else if (ip.isV6()) { + // IPv6 is better designed in this respect. We can compute the IPv6 + // multicast address directly from the IP address, and it gives us + // 24 bits of uniqueness. Collisions aren't likely to be common enough + // to care about. + const uint8_t* const a = + reinterpret_cast(ip.rawIpData()); // NOLINT(hicpp-use-auto,modernize-use-auto) + return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0); + } + return MulticastGroup(); // NOLINT(modernize-return-braced-init-list) + } - /** - * @return Ethernet MAC portion of multicast group - */ - ZT_INLINE const MAC &mac() const noexcept - { return m_mac; } + /** + * @return Ethernet MAC portion of multicast group + */ + ZT_INLINE const MAC& mac() const noexcept + { + return m_mac; + } - /** - * @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4 address - */ - ZT_INLINE uint32_t adi() const - { return m_adi; } + /** + * @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4 + * address + */ + ZT_INLINE uint32_t adi() const + { + return m_adi; + } - ZT_INLINE bool operator==(const MulticastGroup &g) const noexcept - { return ((m_mac == g.m_mac) && (m_adi == g.m_adi)); } + ZT_INLINE bool operator==(const MulticastGroup& g) const noexcept + { + return ((m_mac == g.m_mac) && (m_adi == g.m_adi)); + } - ZT_INLINE bool operator!=(const MulticastGroup &g) const noexcept - { return ((m_mac != g.m_mac) || (m_adi != g.m_adi)); } + ZT_INLINE bool operator!=(const MulticastGroup& g) const noexcept + { + return ((m_mac != g.m_mac) || (m_adi != g.m_adi)); + } - ZT_INLINE bool operator<(const MulticastGroup &g) const noexcept - { - if (m_mac < g.m_mac) - return true; - else if (m_mac == g.m_mac) - return (m_adi < g.m_adi); - return false; - } + ZT_INLINE bool operator<(const MulticastGroup& g) const noexcept + { + if (m_mac < g.m_mac) + return true; + else if (m_mac == g.m_mac) + return (m_adi < g.m_adi); + return false; + } - ZT_INLINE bool operator>(const MulticastGroup &g) const noexcept - { return (g < *this); } + ZT_INLINE bool operator>(const MulticastGroup& g) const noexcept + { + return (g < *this); + } - ZT_INLINE bool operator<=(const MulticastGroup &g) const noexcept - { return !(g < *this); } + ZT_INLINE bool operator<=(const MulticastGroup& g) const noexcept + { + return ! (g < *this); + } - ZT_INLINE bool operator>=(const MulticastGroup &g) const noexcept - { return !(*this < g); } + ZT_INLINE bool operator>=(const MulticastGroup& g) const noexcept + { + return ! (*this < g); + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (m_mac.hashCode() + (unsigned long)m_adi); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (m_mac.hashCode() + (unsigned long)m_adi); + } -private: - MAC m_mac; - uint32_t m_adi; + private: + MAC m_mac; + uint32_t m_adi; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Mutex.hpp b/core/Mutex.hpp index fb5f77b47..ec3206c49 100644 --- a/core/Mutex.hpp +++ b/core/Mutex.hpp @@ -36,122 +36,242 @@ namespace ZeroTier { /** * A simple mutual exclusion lock. */ -class Mutex -{ -public: +class Mutex { + public: #ifdef ZT_USE_PTHREADS - ZT_INLINE Mutex() noexcept { pthread_mutex_init(&_mh,nullptr); } - ZT_INLINE ~Mutex() noexcept { pthread_mutex_destroy(&_mh); } - ZT_INLINE void lock() const noexcept { pthread_mutex_lock(&((const_cast (this))->_mh)); } - ZT_INLINE void unlock() const noexcept { pthread_mutex_unlock(&((const_cast (this))->_mh)); } + ZT_INLINE Mutex() noexcept + { + pthread_mutex_init(&_mh, nullptr); + } + ZT_INLINE ~Mutex() noexcept + { + pthread_mutex_destroy(&_mh); + } + ZT_INLINE void lock() const noexcept + { + pthread_mutex_lock(&((const_cast(this))->_mh)); + } + ZT_INLINE void unlock() const noexcept + { + pthread_mutex_unlock(&((const_cast(this))->_mh)); + } #else - ZT_INLINE Mutex() noexcept : _m() {} - ZT_INLINE void lock() const noexcept { const_cast(this)->_m.lock(); } - ZT_INLINE void unlock() const noexcept { const_cast(this)->_m.unlock(); } + ZT_INLINE Mutex() noexcept : _m() + { + } + ZT_INLINE void lock() const noexcept + { + const_cast(this)->_m.lock(); + } + ZT_INLINE void unlock() const noexcept + { + const_cast(this)->_m.unlock(); + } #endif - class Lock - { - public: - explicit ZT_INLINE Lock(Mutex &m) noexcept : _m(&m) { m.lock(); } - explicit ZT_INLINE Lock(const Mutex &m) noexcept : _m(const_cast(&m)) { _m->lock(); } - ZT_INLINE ~Lock() { _m->unlock(); } - private: - Mutex *const _m; - }; + class Lock { + public: + explicit ZT_INLINE Lock(Mutex& m) noexcept : _m(&m) + { + m.lock(); + } + explicit ZT_INLINE Lock(const Mutex& m) noexcept : _m(const_cast(&m)) + { + _m->lock(); + } + ZT_INLINE ~Lock() + { + _m->unlock(); + } -private: - ZT_INLINE Mutex(const Mutex &) noexcept {} - ZT_INLINE const Mutex &operator=(const Mutex &) noexcept { return *this; } + private: + Mutex* const _m; + }; + + private: + ZT_INLINE Mutex(const Mutex&) noexcept + { + } + ZT_INLINE const Mutex& operator=(const Mutex&) noexcept + { + return *this; + } #ifdef ZT_USE_PTHREADS - pthread_mutex_t _mh; + pthread_mutex_t _mh; #else - std::mutex _m; + std::mutex _m; #endif }; /** * A lock allowing multiple threads to read but making all wait on any writing thread. */ -class RWMutex -{ -public: +class RWMutex { + public: #ifdef ZT_USE_PTHREADS - ZT_INLINE RWMutex() noexcept { pthread_rwlock_init(&_mh,nullptr); } - ZT_INLINE ~RWMutex() noexcept { pthread_rwlock_destroy(&_mh); } - ZT_INLINE void lock() const noexcept { pthread_rwlock_wrlock(&((const_cast (this))->_mh)); } - ZT_INLINE void rlock() const noexcept { pthread_rwlock_rdlock(&((const_cast (this))->_mh)); } - ZT_INLINE void unlock() const noexcept { pthread_rwlock_unlock(&((const_cast (this))->_mh)); } - ZT_INLINE void runlock() const noexcept { pthread_rwlock_unlock(&((const_cast (this))->_mh)); } + ZT_INLINE RWMutex() noexcept + { + pthread_rwlock_init(&_mh, nullptr); + } + ZT_INLINE ~RWMutex() noexcept + { + pthread_rwlock_destroy(&_mh); + } + ZT_INLINE void lock() const noexcept + { + pthread_rwlock_wrlock(&((const_cast(this))->_mh)); + } + ZT_INLINE void rlock() const noexcept + { + pthread_rwlock_rdlock(&((const_cast(this))->_mh)); + } + ZT_INLINE void unlock() const noexcept + { + pthread_rwlock_unlock(&((const_cast(this))->_mh)); + } + ZT_INLINE void runlock() const noexcept + { + pthread_rwlock_unlock(&((const_cast(this))->_mh)); + } #else - ZT_INLINE RWMutex() noexcept : _m() {} - ZT_INLINE void lock() const noexcept { const_cast(this)->_m.lock(); } - ZT_INLINE void rlock() const noexcept { const_cast(this)->_m.lock_shared(); } - ZT_INLINE void unlock() const noexcept { const_cast(this)->_m.unlock(); } - ZT_INLINE void runlock() const noexcept { const_cast(this)->_m.unlock_shared(); } + ZT_INLINE RWMutex() noexcept : _m() + { + } + ZT_INLINE void lock() const noexcept + { + const_cast(this)->_m.lock(); + } + ZT_INLINE void rlock() const noexcept + { + const_cast(this)->_m.lock_shared(); + } + ZT_INLINE void unlock() const noexcept + { + const_cast(this)->_m.unlock(); + } + ZT_INLINE void runlock() const noexcept + { + const_cast(this)->_m.unlock_shared(); + } #endif - /** - * RAAI locker that acquires only the read lock (shared read) - */ - class RLock - { - public: - explicit ZT_INLINE RLock(RWMutex &m) noexcept : _m(&m) { m.rlock(); } - explicit ZT_INLINE RLock(const RWMutex &m) noexcept : _m(const_cast(&m)) { _m->rlock(); } - ZT_INLINE ~RLock() { _m->runlock(); } - private: - RWMutex *const _m; - }; + /** + * RAAI locker that acquires only the read lock (shared read) + */ + class RLock { + public: + explicit ZT_INLINE RLock(RWMutex& m) noexcept : _m(&m) + { + m.rlock(); + } + explicit ZT_INLINE RLock(const RWMutex& m) noexcept : _m(const_cast(&m)) + { + _m->rlock(); + } + ZT_INLINE ~RLock() + { + _m->runlock(); + } - /** - * RAAI locker that acquires the write lock (exclusive write, no readers) - */ - class Lock - { - public: - explicit ZT_INLINE Lock(RWMutex &m) noexcept : _m(&m) { m.lock(); } - explicit ZT_INLINE Lock(const RWMutex &m) noexcept : _m(const_cast(&m)) { _m->lock(); } - ZT_INLINE ~Lock() { _m->unlock(); } - private: - RWMutex *const _m; - }; + private: + RWMutex* const _m; + }; - /** - * RAAI locker that acquires the read lock first and can switch to writing. - * - * Use writing() to acquire the write lock if not already acquired. Use reading() to - * let go of the write lock and go back to only holding the read lock. Note that on - * most platforms there's a brief moment where the lock is unlocked during the - * transition, meaning protected variable states can change. Code must not assume - * that the lock is held constantly if writing() is used to change mode. - */ - class RMaybeWLock - { - public: - explicit ZT_INLINE RMaybeWLock(RWMutex &m) noexcept : _m(&m),_w(false) { m.rlock(); } - explicit ZT_INLINE RMaybeWLock(const RWMutex &m) noexcept : _m(const_cast(&m)),_w(false) { _m->rlock(); } - ZT_INLINE void writing() noexcept { if (!_w) { _w = true; _m->runlock(); _m->lock(); } } - ZT_INLINE void reading() noexcept { if (_w) { _w = false; _m->unlock(); _m->rlock(); } } - ZT_INLINE bool isWriting() const noexcept { return _w; } - ZT_INLINE ~RMaybeWLock() { if (_w) _m->unlock(); else _m->runlock(); } - private: - RWMutex *const _m; - bool _w; - }; + /** + * RAAI locker that acquires the write lock (exclusive write, no readers) + */ + class Lock { + public: + explicit ZT_INLINE Lock(RWMutex& m) noexcept : _m(&m) + { + m.lock(); + } + explicit ZT_INLINE Lock(const RWMutex& m) noexcept : _m(const_cast(&m)) + { + _m->lock(); + } + ZT_INLINE ~Lock() + { + _m->unlock(); + } -private: - ZT_INLINE RWMutex(const RWMutex &) noexcept {} - ZT_INLINE const RWMutex &operator=(const RWMutex &) noexcept { return *this; } + private: + RWMutex* const _m; + }; + + /** + * RAAI locker that acquires the read lock first and can switch to writing. + * + * Use writing() to acquire the write lock if not already acquired. Use reading() to + * let go of the write lock and go back to only holding the read lock. Note that on + * most platforms there's a brief moment where the lock is unlocked during the + * transition, meaning protected variable states can change. Code must not assume + * that the lock is held constantly if writing() is used to change mode. + */ + class RMaybeWLock { + public: + explicit ZT_INLINE RMaybeWLock(RWMutex& m) noexcept + : _m(&m) + , _w(false) + { + m.rlock(); + } + explicit ZT_INLINE RMaybeWLock(const RWMutex& m) noexcept + : _m(const_cast(&m)) + , _w(false) + { + _m->rlock(); + } + ZT_INLINE void writing() noexcept + { + if (! _w) { + _w = true; + _m->runlock(); + _m->lock(); + } + } + ZT_INLINE void reading() noexcept + { + if (_w) { + _w = false; + _m->unlock(); + _m->rlock(); + } + } + ZT_INLINE bool isWriting() const noexcept + { + return _w; + } + ZT_INLINE ~RMaybeWLock() + { + if (_w) + _m->unlock(); + else + _m->runlock(); + } + + private: + RWMutex* const _m; + bool _w; + }; + + private: + ZT_INLINE RWMutex(const RWMutex&) noexcept + { + } + ZT_INLINE const RWMutex& operator=(const RWMutex&) noexcept + { + return *this; + } #ifdef ZT_USE_PTHREADS - pthread_rwlock_t _mh; + pthread_rwlock_t _mh; #else - std::shared_mutex _m; + std::shared_mutex _m; #endif }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Network.cpp b/core/Network.cpp index b119f0fce..b9f7a2906 100644 --- a/core/Network.cpp +++ b/core/Network.cpp @@ -11,21 +11,21 @@ */ /****/ -#include -#include - -#include "Constants.hpp" #include "Network.hpp" -#include "Context.hpp" -#include "MAC.hpp" + #include "Address.hpp" +#include "Buf.hpp" +#include "Constants.hpp" +#include "Context.hpp" #include "InetAddress.hpp" +#include "MAC.hpp" #include "NetworkController.hpp" #include "Peer.hpp" -#include "Trace.hpp" #include "ScopedPtr.hpp" -#include "Buf.hpp" +#include "Trace.hpp" +#include +#include #include namespace ZeroTier { @@ -33,868 +33,1123 @@ namespace ZeroTier { namespace { // Returns true if packet appears valid; pos and proto will be set -bool _ipv6GetPayload(const uint8_t *frameData, unsigned int frameLen, unsigned int &pos, unsigned int &proto) noexcept +bool _ipv6GetPayload(const uint8_t* frameData, unsigned int frameLen, unsigned int& pos, unsigned int& proto) noexcept { - if (frameLen < 40) - return false; - pos = 40; - proto = frameData[6]; - while (pos <= frameLen) { - switch (proto) { - case 0: // hop-by-hop options - case 43: // routing - case 60: // destination options - case 135: // mobility options - if ((pos + 8) > frameLen) - return false; // invalid! - proto = frameData[pos]; - pos += ((unsigned int)frameData[pos + 1] * 8) + 8; - break; + if (frameLen < 40) + return false; + pos = 40; + proto = frameData[6]; + while (pos <= frameLen) { + switch (proto) { + case 0: // hop-by-hop options + case 43: // routing + case 60: // destination options + case 135: // mobility options + if ((pos + 8) > frameLen) + return false; // invalid! + proto = frameData[pos]; + pos += ((unsigned int)frameData[pos + 1] * 8) + 8; + break; - //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway - //case 50: - //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff - default: - return true; - } - } - return false; // overflow == invalid + // case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway + // case 50: + // case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff + default: + return true; + } + } + return false; // overflow == invalid } -enum _doZtFilterResult -{ - DOZTFILTER_NO_MATCH, - DOZTFILTER_DROP, - DOZTFILTER_REDIRECT, - DOZTFILTER_ACCEPT, - DOZTFILTER_SUPER_ACCEPT +enum _doZtFilterResult { + DOZTFILTER_NO_MATCH, + DOZTFILTER_DROP, + DOZTFILTER_REDIRECT, + DOZTFILTER_ACCEPT, + DOZTFILTER_SUPER_ACCEPT }; ZT_INLINE _doZtFilterResult _doZtFilter( - const Context &ctx, - Trace::RuleResultLog &rrl, - const NetworkConfig &nconf, - const Member *membership, // can be NULL - const bool inbound, - const Address &ztSource, - Address &ztDest, // MUTABLE -- is changed on REDIRECT actions - const MAC &macSource, - const MAC &macDest, - const uint8_t *const frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - const ZT_VirtualNetworkRule *rules, // cannot be NULL - const unsigned int ruleCount, - Address &cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise - unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE - bool &ccWatch, // MUTABLE -- set to true for WATCH target as opposed to normal TEE - uint8_t &qosBucket) noexcept // MUTABLE -- set to the value of the argument provided to PRIORITY + const Context& ctx, + Trace::RuleResultLog& rrl, + const NetworkConfig& nconf, + const Member* membership, // can be NULL + const bool inbound, + const Address& ztSource, + Address& ztDest, // MUTABLE -- is changed on REDIRECT actions + const MAC& macSource, + const MAC& macDest, + const uint8_t* const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const ZT_VirtualNetworkRule* rules, // cannot be NULL + const unsigned int ruleCount, + Address& cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise + unsigned int& ccLength, // MUTABLE -- set to length of packet payload to TEE + bool& ccWatch, // MUTABLE -- set to true for WATCH target as opposed to normal TEE + uint8_t& qosBucket) noexcept // MUTABLE -- set to the value of the argument provided to PRIORITY { - // Set to true if we are a TEE/REDIRECT/WATCH target - bool superAccept = false; + // Set to true if we are a TEE/REDIRECT/WATCH target + bool superAccept = false; - // The default match state for each set of entries starts as 'true' since an - // ACTION with no MATCH entries preceding it is always taken. - uint8_t thisSetMatches = 1; + // The default match state for each set of entries starts as 'true' since an + // ACTION with no MATCH entries preceding it is always taken. + uint8_t thisSetMatches = 1; - rrl.clear(); + rrl.clear(); - for (unsigned int rn = 0; rn < ruleCount; ++rn) { - const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3fU); + for (unsigned int rn = 0; rn < ruleCount; ++rn) { + const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3fU); - // First check if this is an ACTION - if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) { - if (thisSetMatches) { - switch (rt) { - case ZT_NETWORK_RULE_ACTION_PRIORITY: - qosBucket = (rules[rn].v.qosBucket >= 0 && rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority) - return DOZTFILTER_ACCEPT; + // First check if this is an ACTION + if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) { + if (thisSetMatches) { + switch (rt) { + case ZT_NETWORK_RULE_ACTION_PRIORITY: + qosBucket = (rules[rn].v.qosBucket >= 0 && rules[rn].v.qosBucket <= 8) + ? rules[rn].v.qosBucket + : 4; // 4 = default bucket (no priority) + return DOZTFILTER_ACCEPT; - case ZT_NETWORK_RULE_ACTION_DROP: - return DOZTFILTER_DROP; + case ZT_NETWORK_RULE_ACTION_DROP: + return DOZTFILTER_DROP; - case ZT_NETWORK_RULE_ACTION_ACCEPT: - return (superAccept ? DOZTFILTER_SUPER_ACCEPT : DOZTFILTER_ACCEPT); // match, accept packet + case ZT_NETWORK_RULE_ACTION_ACCEPT: + return (superAccept ? DOZTFILTER_SUPER_ACCEPT : DOZTFILTER_ACCEPT); // match, accept packet - // These are initially handled together since preliminary logic is common - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: { - const Address fwdAddr(rules[rn].v.fwd.address); - if (fwdAddr == ztSource) { - // Skip as no-op since source is target - } else if (fwdAddr == ctx.identity.address()) { - if (inbound) { - return DOZTFILTER_SUPER_ACCEPT; - } else { - } - } else if (fwdAddr == ztDest) { - } else { - if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { - ztDest = fwdAddr; - return DOZTFILTER_REDIRECT; - } else { - cc = fwdAddr; - ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; - ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); - } - } - } - continue; + // These are initially handled together since preliminary logic is common + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: { + const Address fwdAddr(rules[rn].v.fwd.address); + if (fwdAddr == ztSource) { + // Skip as no-op since source is target + } + else if (fwdAddr == ctx.identity.address()) { + if (inbound) { + return DOZTFILTER_SUPER_ACCEPT; + } + else { + } + } + else if (fwdAddr == ztDest) { + } + else { + if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { + ztDest = fwdAddr; + return DOZTFILTER_REDIRECT; + } + else { + cc = fwdAddr; + ccLength = (rules[rn].v.fwd.length != 0) + ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) + ? frameLen + : (unsigned int)rules[rn].v.fwd.length) + : frameLen; + ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); + } + } + } + continue; - case ZT_NETWORK_RULE_ACTION_BREAK: - return DOZTFILTER_NO_MATCH; + case ZT_NETWORK_RULE_ACTION_BREAK: + return DOZTFILTER_NO_MATCH; - // Unrecognized ACTIONs are ignored as no-ops - default: - continue; - } - } else { - // If this is an incoming packet and we are a TEE or REDIRECT target, we should - // super-accept if we accept at all. This will cause us to accept redirected or - // tee'd packets in spite of MAC and ZT addressing checks. - if (inbound) { - switch (rt) { - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - if (ctx.identity.address().toInt() == rules[rn].v.fwd.address) - superAccept = true; - break; - default: - break; - } - } + // Unrecognized ACTIONs are ignored as no-ops + default: + continue; + } + } + else { + // If this is an incoming packet and we are a TEE or REDIRECT target, we should + // super-accept if we accept at all. This will cause us to accept redirected or + // tee'd packets in spite of MAC and ZT addressing checks. + if (inbound) { + switch (rt) { + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + if (ctx.identity.address().toInt() == rules[rn].v.fwd.address) + superAccept = true; + break; + default: + break; + } + } - thisSetMatches = 1; // reset to default true for next batch of entries - continue; - } - } + thisSetMatches = 1; // reset to default true for next batch of entries + continue; + } + } - // Circuit breaker: no need to evaluate an AND if the set's match state - // is currently false since anything AND false is false. - if ((!thisSetMatches) && (!(rules[rn].t & 0x40U))) { - rrl.logSkipped(rn, thisSetMatches); - continue; - } + // Circuit breaker: no need to evaluate an AND if the set's match state + // is currently false since anything AND false is false. + if ((! thisSetMatches) && (! (rules[rn].t & 0x40U))) { + rrl.logSkipped(rn, thisSetMatches); + continue; + } - // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) - uint8_t thisRuleMatches = 0; - uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed - switch (rt) { - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); - break; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac) == macSource); - break; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac) == macDest); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12), 4, 0))); - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16), 4, 0))); - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8), 16, 0))); - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24), 16, 0))); - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); - } else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { - const uint8_t tosMasked = (((frameData[0] << 4U) & 0xf0U) | ((frameData[1] >> 4U) & 0x0fU)) & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0, proto = 0; - if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - if (frameData[9] == 0x01) { // IP protocol == ICMP - const unsigned int ihl = (frameData[0] & 0xfU) * 4; - if (frameLen >= (ihl + 2)) { - if (rules[rn].v.icmp.type == frameData[ihl]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[ihl + 1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = 1; - } - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0, proto = 0; - if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { - if ((proto == 0x3a) && (frameLen >= (pos + 2))) { - if (rules[rn].v.icmp.type == frameData[pos]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[pos + 1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = 1; - } - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xfU); - int p = -1; - switch (frameData[9]) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (headerLen + 4)) { - unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); - p = (int)(frameData[pos++] << 8U); - p |= (int)frameData[pos]; - } - break; - } + // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) + uint8_t thisRuleMatches = 0; + uint64_t ownershipVerificationMask = + 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed + switch (rt) { + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac) == macSource); + break; + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac) == macDest); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = + (uint8_t)(InetAddress((const void*)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask) + .containsAddress(InetAddress((const void*)(frameData + 12), 4, 0))); + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = + (uint8_t)(InetAddress((const void*)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask) + .containsAddress(InetAddress((const void*)(frameData + 16), 4, 0))); + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + thisRuleMatches = (uint8_t)(InetAddress((const void*)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask) + .containsAddress(InetAddress((const void*)(frameData + 8), 16, 0))); + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + thisRuleMatches = + (uint8_t)(InetAddress((const void*)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask) + .containsAddress(InetAddress((const void*)(frameData + 24), 16, 0))); + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; + thisRuleMatches = + (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); + } + else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + const uint8_t tosMasked = + (((frameData[0] << 4U) & 0xf0U) | ((frameData[1] >> 4U) & 0x0fU)) & rules[rn].v.ipTos.mask; + thisRuleMatches = + (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + if (frameData[9] == 0x01) { // IP protocol == ICMP + const unsigned int ihl = (frameData[0] & 0xfU) * 4; + if (frameLen >= (ihl + 2)) { + if (rules[rn].v.icmp.type == frameData[ihl]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[ihl + 1] == rules[rn].v.icmp.code); + } + else { + thisRuleMatches = 1; + } + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + if ((proto == 0x3a) && (frameLen >= (pos + 2))) { + if (rules[rn].v.icmp.type == frameData[pos]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[pos + 1] == rules[rn].v.icmp.code); + } + else { + thisRuleMatches = 1; + } + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xfU); + int p = -1; + switch (frameData[9]) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (headerLen + 4)) { + unsigned int pos = + headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); + p = (int)(frameData[pos++] << 8U); + p |= (int)frameData[pos]; + } + break; + } - thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0, proto = 0; - if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { - int p = -1; - switch (proto) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (pos + 4)) { - if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2; - p = (int)(frameData[pos++] << 8U); - p |= (int)frameData[pos]; - } - break; - } - thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - } else { - thisRuleMatches = 0; - } - } else { - thisRuleMatches = 0; - } - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { - uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; - if (macDest.isMulticast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; - if (macDest.isBroadcast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; - if (ownershipVerificationMask == 1) { - ownershipVerificationMask = 0; - InetAddress src; - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { - src.set((const void *)(frameData + 12), 4, 0); - } else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { - // IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local. - if ((frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87) || (frameData[40] == 0x88))) { - if (frameData[40] == 0x87) { - // Neighbor solicitations contain no reliable source address, so we implement a small - // hack by considering them authenticated. Otherwise you would pretty much have to do - // this manually in the rule set for IPv6 to work at all. - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - } else { - // Neighbor advertisements on the other hand can absolutely be authenticated. - src.set((const void *)(frameData + 40 + 8), 16, 0); - } - } else { - // Other IPv6 packets can be handled normally - src.set((const void *)(frameData + 8), 16, 0); - } - } else if ((etherType == ZT_ETHERTYPE_ARP) && (frameLen >= 28)) { - src.set((const void *)(frameData + 14), 4, 0); - } - if (inbound) { - if (membership) { - if ((src) && (membership->peerOwnsAddress< InetAddress >(nconf, src))) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - if (membership->peerOwnsAddress< MAC >(nconf, macSource)) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; - } - } else { - for (unsigned int i = 0; i < nconf.certificateOfOwnershipCount; ++i) { - if ((src) && (nconf.certificatesOfOwnership[i].owns(src))) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - if (nconf.certificatesOfOwnership[i].owns(macSource)) - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; - } - } - } - cf |= ownershipVerificationMask; - if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20) && (frameData[9] == 0x06)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xfU); - cf |= (uint64_t)frameData[headerLen + 13]; - cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0, proto = 0; - if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { - if ((proto == 0x06) && (frameLen > (pos + 14))) { - cf |= (uint64_t)frameData[pos + 13]; - cf |= (((uint64_t)(frameData[pos + 12] & 0x0fU)) << 8U); - } - } - } - thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); - } - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0]) && (frameLen <= (unsigned int)rules[rn].v.frameSize[1])); - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - thisRuleMatches = (uint8_t)((uint32_t)(Utils::random() & 0xffffffffULL) <= rules[rn].v.randomProbability); - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { - const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate()); - if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { - const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0); - if (remoteTag) { - const uint32_t ltv = localTag->value(); - const uint32_t rtv = remoteTag->value(); - if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { - const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); - thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { - thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { - thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { - thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { - thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value) && (rtv == rules[rn].v.tag.value)); - } else { // sanity check, can't really happen - thisRuleMatches = 0; - } - } else { - if ((inbound) && (!superAccept)) { - thisRuleMatches = 0; - } else { - // Outbound side is not strict since if we have to match both tags and - // we are sending a first packet to a recipient, we probably do not know - // about their tags yet. They will filter on inbound and we will filter - // once we get their tag. If we are a tee/redirect target we are also - // not strict since we likely do not have these tags. - thisRuleMatches = 1; - } - } - } else { - thisRuleMatches = 0; - } - } - break; - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { - if (superAccept) { - thisRuleMatches = 1; - } else if (((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER) && (inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) && (!inbound))) { - const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0); - if (remoteTag) { - thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); - } else { - if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { - // If we are checking the receiver and this is an outbound packet, we - // can't be strict since we may not yet know the receiver's tag. - thisRuleMatches = 1; - } else { - thisRuleMatches = 0; - } - } - } else { // sender and outbound or receiver and inbound - const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate()); - if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { - thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); - } else { - thisRuleMatches = 0; - } - } - } - break; - case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { - uint64_t integer = 0; - const unsigned int bits = (rules[rn].v.intRange.format & 63U) + 1; - const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8 - if ((rules[rn].v.intRange.format & 0x80U) == 0) { - // Big-endian - unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); - const unsigned int eof = idx + bytes; - if (eof <= frameLen) { - while (idx < eof) { - integer <<= 8U; - integer |= frameData[idx++]; - } - } - integer &= 0xffffffffffffffffULL >> (64 - bits); - } else { - // Little-endian - unsigned int idx = rules[rn].v.intRange.idx; - const unsigned int eof = idx + bytes; - if (eof <= frameLen) { - while (idx < eof) { - integer >>= 8U; - integer |= ((uint64_t)frameData[idx++]) << 56U; - } - } - integer >>= (64 - bits); - } - thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start) && (integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end))); - } - break; + thisRuleMatches = + (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) + : (uint8_t)0; + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + int p = -1; + switch (proto) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (pos + 4)) { + if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) + pos += 2; + p = (int)(frameData[pos++] << 8U); + p |= (int)frameData[pos]; + } + break; + } + thisRuleMatches = + (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) + : (uint8_t)0; + } + else { + thisRuleMatches = 0; + } + } + else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { + uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; + if (macDest.isMulticast()) + cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; + if (macDest.isBroadcast()) + cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; + if (ownershipVerificationMask == 1) { + ownershipVerificationMask = 0; + InetAddress src; + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + src.set((const void*)(frameData + 12), 4, 0); + } + else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + // IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or + // link-local. + if ((frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) + && ((frameData[40] == 0x87) || (frameData[40] == 0x88))) { + if (frameData[40] == 0x87) { + // Neighbor solicitations contain no reliable source address, so we implement a small + // hack by considering them authenticated. Otherwise you would pretty much have to do + // this manually in the rule set for IPv6 to work at all. + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + } + else { + // Neighbor advertisements on the other hand can absolutely be authenticated. + src.set((const void*)(frameData + 40 + 8), 16, 0); + } + } + else { + // Other IPv6 packets can be handled normally + src.set((const void*)(frameData + 8), 16, 0); + } + } + else if ((etherType == ZT_ETHERTYPE_ARP) && (frameLen >= 28)) { + src.set((const void*)(frameData + 14), 4, 0); + } + if (inbound) { + if (membership) { + if ((src) && (membership->peerOwnsAddress(nconf, src))) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + if (membership->peerOwnsAddress(nconf, macSource)) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; + } + } + else { + for (unsigned int i = 0; i < nconf.certificateOfOwnershipCount; ++i) { + if ((src) && (nconf.certificatesOfOwnership[i].owns(src))) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + if (nconf.certificatesOfOwnership[i].owns(macSource)) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; + } + } + } + cf |= ownershipVerificationMask; + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20) && (frameData[9] == 0x06)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xfU); + cf |= (uint64_t)frameData[headerLen + 13]; + cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U); + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + if ((proto == 0x06) && (frameLen > (pos + 14))) { + cf |= (uint64_t)frameData[pos + 13]; + cf |= (((uint64_t)(frameData[pos + 12] & 0x0fU)) << 8U); + } + } + } + thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); + } break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0]) && (frameLen <= (unsigned int)rules[rn].v.frameSize[1])); + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + thisRuleMatches = + (uint8_t)((uint32_t)(Utils::random() & 0xffffffffULL) <= rules[rn].v.randomProbability); + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { + const TagCredential* const localTag = std::lower_bound( + &(nconf.tags[0]), + &(nconf.tags[nconf.tagCount]), + rules[rn].v.tag.id, + TagCredential::IdComparePredicate()); + if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { + const TagCredential* const remoteTag = + ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential*)0); + if (remoteTag) { + const uint32_t ltv = localTag->value(); + const uint32_t rtv = remoteTag->value(); + if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { + const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); + thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { + thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { + thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { + thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { + thisRuleMatches = + (uint8_t)((ltv == rules[rn].v.tag.value) && (rtv == rules[rn].v.tag.value)); + } + else { // sanity check, can't really happen + thisRuleMatches = 0; + } + } + else { + if ((inbound) && (! superAccept)) { + thisRuleMatches = 0; + } + else { + // Outbound side is not strict since if we have to match both tags and + // we are sending a first packet to a recipient, we probably do not know + // about their tags yet. They will filter on inbound and we will filter + // once we get their tag. If we are a tee/redirect target we are also + // not strict since we likely do not have these tags. + thisRuleMatches = 1; + } + } + } + else { + thisRuleMatches = 0; + } + } break; + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { + if (superAccept) { + thisRuleMatches = 1; + } + else if ( + ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER) && (inbound)) + || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) && (! inbound))) { + const TagCredential* const remoteTag = + ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential*)0); + if (remoteTag) { + thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); + } + else { + if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { + // If we are checking the receiver and this is an outbound packet, we + // can't be strict since we may not yet know the receiver's tag. + thisRuleMatches = 1; + } + else { + thisRuleMatches = 0; + } + } + } + else { // sender and outbound or receiver and inbound + const TagCredential* const localTag = std::lower_bound( + &(nconf.tags[0]), + &(nconf.tags[nconf.tagCount]), + rules[rn].v.tag.id, + TagCredential::IdComparePredicate()); + if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { + thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); + } + else { + thisRuleMatches = 0; + } + } + } break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { + uint64_t integer = 0; + const unsigned int bits = (rules[rn].v.intRange.format & 63U) + 1; + const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8 + if ((rules[rn].v.intRange.format & 0x80U) == 0) { + // Big-endian + unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); + const unsigned int eof = idx + bytes; + if (eof <= frameLen) { + while (idx < eof) { + integer <<= 8U; + integer |= frameData[idx++]; + } + } + integer &= 0xffffffffffffffffULL >> (64 - bits); + } + else { + // Little-endian + unsigned int idx = rules[rn].v.intRange.idx; + const unsigned int eof = idx + bytes; + if (eof <= frameLen) { + while (idx < eof) { + integer >>= 8U; + integer |= ((uint64_t)frameData[idx++]) << 56U; + } + } + integer >>= (64 - bits); + } + thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start) && (integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end))); + } break; - // The result of an unsupported MATCH is configurable at the network - // level via a flag. - default: - thisRuleMatches = (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0); - break; - } + // The result of an unsupported MATCH is configurable at the network + // level via a flag. + default: + thisRuleMatches = + (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0); + break; + } - rrl.log(rn, thisRuleMatches, thisSetMatches); + rrl.log(rn, thisRuleMatches, thisSetMatches); - if ((rules[rn].t & 0x40U)) - thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); - else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); - } + if ((rules[rn].t & 0x40U)) + thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); + else + thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); + } - return DOZTFILTER_NO_MATCH; + return DOZTFILTER_NO_MATCH; } -} // anonymous namespace +} // anonymous namespace const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL), 0); -Network::Network(const Context &ctx, const CallContext &cc, uint64_t nwid, const Fingerprint &controllerFingerprint, void *uptr, const NetworkConfig *nconf) : - m_ctx(ctx), - m_uPtr(uptr), - m_id(nwid), - m_mac(ctx.identity.address(), nwid), - m_portInitialized(false), - m_destroyed(false), - m_lastConfigUpdate(0), - _netconfFailure(NETCONF_FAILURE_NONE) +Network::Network( + const Context& ctx, + const CallContext& cc, + uint64_t nwid, + const Fingerprint& controllerFingerprint, + void* uptr, + const NetworkConfig* nconf) + : m_ctx(ctx) + , m_uPtr(uptr) + , m_id(nwid) + , m_mac(ctx.identity.address(), nwid) + , m_portInitialized(false) + , m_destroyed(false) + , m_lastConfigUpdate(0) + , _netconfFailure(NETCONF_FAILURE_NONE) { - if (controllerFingerprint) - m_controllerFingerprint = controllerFingerprint; + if (controllerFingerprint) + m_controllerFingerprint = controllerFingerprint; - if (nconf) { - this->setConfiguration(cc, *nconf, false); - m_lastConfigUpdate = 0; // still want to re-request since it's likely outdated - } else { - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; + if (nconf) { + this->setConfiguration(cc, *nconf, false); + m_lastConfigUpdate = 0; // still want to re-request since it's likely outdated + } + else { + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; - bool got = false; - try { - Dictionary dict; - Vector< uint8_t > nconfData(m_ctx.store->get(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1)); - if (nconfData.size() > 2) { - nconfData.push_back(0); - if (dict.decode(nconfData.data(), (unsigned int)nconfData.size())) { - try { - ScopedPtr< NetworkConfig > nconf2(new NetworkConfig()); - if (nconf2->fromDictionary(dict)) { - this->setConfiguration(cc, *nconf2, false); - m_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated - got = true; - } - } catch (...) {} - } - } - } catch (...) {} + bool got = false; + try { + Dictionary dict; + Vector nconfData(m_ctx.store->get(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1)); + if (nconfData.size() > 2) { + nconfData.push_back(0); + if (dict.decode(nconfData.data(), (unsigned int)nconfData.size())) { + try { + ScopedPtr nconf2(new NetworkConfig()); + if (nconf2->fromDictionary(dict)) { + this->setConfiguration(cc, *nconf2, false); + m_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated + got = true; + } + } + catch (...) { + } + } + } + } + catch (...) { + } - if (!got) - m_ctx.store->put(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1, "\n", 1); - } + if (! got) + m_ctx.store->put(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1, "\n", 1); + } - if (!m_portInitialized) { - ZT_VirtualNetworkConfig ctmp; - m_externalConfig(&ctmp); - m_ctx.cb.virtualNetworkConfigFunction(reinterpret_cast(m_ctx.node), m_ctx.uPtr, cc.tPtr, m_id, &m_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); - m_portInitialized = true; - } + if (! m_portInitialized) { + ZT_VirtualNetworkConfig ctmp; + m_externalConfig(&ctmp); + m_ctx.cb.virtualNetworkConfigFunction( + reinterpret_cast(m_ctx.node), + m_ctx.uPtr, + cc.tPtr, + m_id, + &m_uPtr, + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, + &ctmp); + m_portInitialized = true; + } } Network::~Network() { - m_memberships_l.lock(); - m_config_l.lock(); - m_config_l.unlock(); - m_memberships_l.unlock(); + m_memberships_l.lock(); + m_config_l.lock(); + m_config_l.unlock(); + m_memberships_l.unlock(); - ZT_VirtualNetworkConfig ctmp; - m_externalConfig(&ctmp); + ZT_VirtualNetworkConfig ctmp; + m_externalConfig(&ctmp); - if (m_destroyed) { - // This is done in Node::leave() so we can pass tPtr properly - //m_ctx.node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); - } else { - m_ctx.cb.virtualNetworkConfigFunction(reinterpret_cast(m_ctx.node), m_ctx.uPtr, nullptr, m_id, &m_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, &ctmp); - } + if (m_destroyed) { + // This is done in Node::leave() so we can pass tPtr properly + // m_ctx.node->configureVirtualNetworkPort((void + // *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); + } + else { + m_ctx.cb.virtualNetworkConfigFunction( + reinterpret_cast(m_ctx.node), + m_ctx.uPtr, + nullptr, + m_id, + &m_uPtr, + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, + &ctmp); + } } bool Network::filterOutgoingPacket( - const CallContext &cc, - const bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - uint8_t &qosBucket) + const CallContext& cc, + const bool noTee, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + uint8_t& qosBucket) { - Trace::RuleResultLog rrl, crrl; - Address ztFinalDest(ztDest); - int localCapabilityIndex = -1; - int accept = 0; - Address ccNodeAddress; - unsigned int ccLength = 0; - bool ccWatch = false; + Trace::RuleResultLog rrl, crrl; + Address ztFinalDest(ztDest); + int localCapabilityIndex = -1; + int accept = 0; + Address ccNodeAddress; + unsigned int ccLength = 0; + bool ccWatch = false; - Mutex::Lock l1(m_memberships_l); - Mutex::Lock l2(m_config_l); + Mutex::Lock l1(m_memberships_l); + Mutex::Lock l2(m_config_l); - Member *membership; - if (ztDest) { - Map::iterator mm(m_memberships.find(ztDest)); - membership = (mm == m_memberships.end()) ? nullptr : &(mm->second); - } else { - membership = nullptr; - } + Member* membership; + if (ztDest) { + Map::iterator mm(m_memberships.find(ztDest)); + membership = (mm == m_memberships.end()) ? nullptr : &(mm->second); + } + else { + membership = nullptr; + } - switch (_doZtFilter(m_ctx, rrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, ccNodeAddress, ccLength, ccWatch, qosBucket)) { + switch (_doZtFilter( + m_ctx, + rrl, + m_config, + membership, + false, + ztSource, + ztFinalDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + m_config.rules, + m_config.ruleCount, + ccNodeAddress, + ccLength, + ccWatch, + qosBucket)) { + case DOZTFILTER_NO_MATCH: { + for (unsigned int c = 0; c < m_config.capabilityCount; ++c) { + ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match + Address cc2; + unsigned int ccLength2 = 0; + bool ccWatch2 = false; + switch (_doZtFilter( + m_ctx, + crrl, + m_config, + membership, + false, + ztSource, + ztFinalDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + m_config.capabilities[c].rules(), + m_config.capabilities[c].ruleCount(), + cc2, + ccLength2, + ccWatch2, + qosBucket)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an + // anti-pattern + break; - case DOZTFILTER_NO_MATCH: { - for (unsigned int c = 0; c < m_config.capabilityCount; ++c) { - ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch (_doZtFilter(m_ctx, crrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.capabilities[c].rules(), m_config.capabilities[c].ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in + // _doZtFilter() + case DOZTFILTER_ACCEPT: + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities + localCapabilityIndex = (int)c; + accept = 1; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities - localCapabilityIndex = (int)c; - accept = 1; + if ((! noTee) && (cc2)) { + // TODO + /* + Packet outp(cc2,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength2); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ + } - if ((!noTee) && (cc2)) { - // TODO - /* - Packet outp(cc2,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ - } + break; + } + if (accept) + break; + } + } break; - break; - } - if (accept) - break; - } - } - break; + case DOZTFILTER_DROP: + m_ctx.t->networkFilter( + cc, + 0xadea5a2a, + m_id, + rrl.l, + nullptr, + 0, + 0, + ztSource, + ztDest, + macSource, + macDest, + (uint16_t)frameLen, + frameData, + (uint16_t)etherType, + (uint16_t)vlanId, + noTee, + false, + 0); + return false; - case DOZTFILTER_DROP: - m_ctx.t->networkFilter(cc, 0xadea5a2a, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, 0); - return false; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; + break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; - break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; + break; + } - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; - break; - } + if (accept != 0) { + if ((! noTee) && (ccNodeAddress)) { + // TODO + /* + Packet outp(cc,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ + } - if (accept != 0) { - if ((!noTee) && (ccNodeAddress)) { - // TODO - /* - Packet outp(cc,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ - } + if ((ztDest != ztFinalDest) && (ztFinalDest)) { + // TODO + /* + Packet outp(ztFinalDest,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x04); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,frameLen); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ - if ((ztDest != ztFinalDest) && (ztFinalDest)) { - // TODO - /* - Packet outp(ztFinalDest,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x04); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ + // DROP locally since we redirected + accept = 0; + } + } - // DROP locally since we redirected - accept = 0; - } - } + if (localCapabilityIndex >= 0) { + const CapabilityCredential& cap = m_config.capabilities[localCapabilityIndex]; + m_ctx.t->networkFilter( + cc, + 0x56ff1a93, + m_id, + rrl.l, + crrl.l, + cap.id(), + cap.timestamp(), + ztSource, + ztDest, + macSource, + macDest, + (uint16_t)frameLen, + frameData, + (uint16_t)etherType, + (uint16_t)vlanId, + noTee, + false, + accept); + } + else { + m_ctx.t->networkFilter( + cc, + 0x112fbbab, + m_id, + rrl.l, + nullptr, + 0, + 0, + ztSource, + ztDest, + macSource, + macDest, + (uint16_t)frameLen, + frameData, + (uint16_t)etherType, + (uint16_t)vlanId, + noTee, + false, + accept); + } - if (localCapabilityIndex >= 0) { - const CapabilityCredential &cap = m_config.capabilities[localCapabilityIndex]; - m_ctx.t->networkFilter(cc, 0x56ff1a93, m_id, rrl.l, crrl.l, cap.id(), cap.timestamp(), ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept); - } else { - m_ctx.t->networkFilter(cc, 0x112fbbab, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept); - } - - return (accept != 0); + return (accept != 0); } int Network::filterIncomingPacket( - const CallContext &cc, - const SharedPtr< Peer > &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId) + const CallContext& cc, + const SharedPtr& sourcePeer, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId) { - Address ztFinalDest(ztDest); - Trace::RuleResultLog rrl, crrl; - int accept = 0; - Address ccNodeAddress; - unsigned int ccLength = 0; - bool ccWatch = false; - const CapabilityCredential *c = nullptr; + Address ztFinalDest(ztDest); + Trace::RuleResultLog rrl, crrl; + int accept = 0; + Address ccNodeAddress; + unsigned int ccLength = 0; + bool ccWatch = false; + const CapabilityCredential* c = nullptr; - uint8_t qosBucket = 255; // For incoming packets this is a dummy value + uint8_t qosBucket = 255; // For incoming packets this is a dummy value - Mutex::Lock l1(m_memberships_l); - Mutex::Lock l2(m_config_l); + Mutex::Lock l1(m_memberships_l); + Mutex::Lock l2(m_config_l); - Member &membership = m_memberships[sourcePeer->address()]; + Member& membership = m_memberships[sourcePeer->address()]; - switch (_doZtFilter(m_ctx, rrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, ccNodeAddress, ccLength, ccWatch, qosBucket)) { + switch (_doZtFilter( + m_ctx, + rrl, + m_config, + &membership, + true, + sourcePeer->address(), + ztFinalDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + m_config.rules, + m_config.ruleCount, + ccNodeAddress, + ccLength, + ccWatch, + qosBucket)) { + case DOZTFILTER_NO_MATCH: { + Member::CapabilityIterator mci(membership, m_config); + while ((c = mci.next())) { + ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match + Address cc2; + unsigned int ccLength2 = 0; + bool ccWatch2 = false; + switch (_doZtFilter( + m_ctx, + crrl, + m_config, + &membership, + true, + sourcePeer->address(), + ztFinalDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + c->rules(), + c->ruleCount(), + cc2, + ccLength2, + ccWatch2, + qosBucket)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an + // anti-pattern + break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in + // _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; // super-ACCEPT + break; + } - case DOZTFILTER_NO_MATCH: { - Member::CapabilityIterator mci(membership, m_config); - while ((c = mci.next())) { - ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch (_doZtFilter(m_ctx, crrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, c->rules(), c->ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } + if (accept) { + if (cc2) { + // TODO + /* + Packet outp(cc2,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength2); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ + } + break; + } + } + } break; - if (accept) { - if (cc2) { - // TODO - /* - Packet outp(cc2,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ - } - break; - } - } - } - break; + case DOZTFILTER_DROP: + // if (_config.remoteTraceTarget) + // m_ctx.t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability + //*)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + return 0; // DROP - case DOZTFILTER_DROP: - //if (_config.remoteTraceTarget) - // m_ctx.t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); - return 0; // DROP + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; // super-ACCEPT + break; + } - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } + if (accept) { + if (ccNodeAddress) { + // TODO + /* + Packet outp(cc,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ + } - if (accept) { - if (ccNodeAddress) { - // TODO - /* - Packet outp(cc,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ - } + if ((ztDest != ztFinalDest) && (ztFinalDest)) { + // TODO + /* + Packet outp(ztFinalDest,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x0a); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,frameLen); + outp.compress(); + m_ctx.sw->send(tPtr,outp,true); + */ - if ((ztDest != ztFinalDest) && (ztFinalDest)) { - // TODO - /* - Packet outp(ztFinalDest,m_ctx.identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x0a); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - m_ctx.sw->send(tPtr,outp,true); - */ + // if (_config.remoteTraceTarget) + // m_ctx.t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog + //*)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + return 0; // DROP locally, since we redirected + } + } - //if (_config.remoteTraceTarget) - // m_ctx.t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); - return 0; // DROP locally, since we redirected - } - } - - //if (_config.remoteTraceTarget) - // m_ctx.t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); - return accept; + // if (_config.remoteTraceTarget) + // m_ctx.t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog + //*)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); + return accept; } -void Network::multicastSubscribe(const CallContext &cc, const MulticastGroup &mg) +void Network::multicastSubscribe(const CallContext& cc, const MulticastGroup& mg) { - Mutex::Lock l(m_myMulticastGroups_l); - if (!std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)) { - m_myMulticastGroups.insert(std::upper_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg), mg); - Mutex::Lock l2(m_memberships_l); - m_announceMulticastGroups(cc.tPtr, true); - } + Mutex::Lock l(m_myMulticastGroups_l); + if (! std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)) { + m_myMulticastGroups.insert(std::upper_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg), mg); + Mutex::Lock l2(m_memberships_l); + m_announceMulticastGroups(cc.tPtr, true); + } } -void Network::multicastUnsubscribe(const MulticastGroup &mg) +void Network::multicastUnsubscribe(const MulticastGroup& mg) { - Mutex::Lock l(m_myMulticastGroups_l); - Vector< MulticastGroup >::iterator i(std::lower_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)); - if ((i != m_myMulticastGroups.end()) && (*i == mg)) - m_myMulticastGroups.erase(i); + Mutex::Lock l(m_myMulticastGroups_l); + Vector::iterator i(std::lower_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)); + if ((i != m_myMulticastGroups.end()) && (*i == mg)) + m_myMulticastGroups.erase(i); } -uint64_t Network::handleConfigChunk(const CallContext &cc, uint64_t packetId, const SharedPtr< Peer > &source, const Buf &chunk, int ptr, int size) +uint64_t Network::handleConfigChunk( + const CallContext& cc, + uint64_t packetId, + const SharedPtr& source, + const Buf& chunk, + int ptr, + int size) { - // If the controller's full fingerprint is known or was explicitly specified on join(), - // require that the controller's identity match. Otherwise learn it. - if (m_controllerFingerprint) { - if (source->identity().fingerprint() != m_controllerFingerprint) - return 0; - } else { - m_controllerFingerprint = source->identity().fingerprint(); - } + // If the controller's full fingerprint is known or was explicitly specified on join(), + // require that the controller's identity match. Otherwise learn it. + if (m_controllerFingerprint) { + if (source->identity().fingerprint() != m_controllerFingerprint) + return 0; + } + else { + m_controllerFingerprint = source->identity().fingerprint(); + } - return 0; + return 0; #if 0 if (_destroyed) return 0; @@ -1027,483 +1282,516 @@ uint64_t Network::handleConfigChunk(const CallContext &cc, uint64_t packetId, co #endif } -int Network::setConfiguration(const CallContext &cc, const NetworkConfig &nconf, bool saveToDisk) +int Network::setConfiguration(const CallContext& cc, const NetworkConfig& nconf, bool saveToDisk) { - if (m_destroyed) - return 0; + if (m_destroyed) + return 0; - // _lock is NOT locked when this is called - try { - if ((nconf.issuedTo != m_ctx.identity.address()) || (nconf.networkId != m_id)) - return 0; // invalid config that is not for us or not for this network - if ((!Utils::allZero(nconf.issuedToFingerprintHash, ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash, m_ctx.identity.fingerprint().hash, ZT_FINGERPRINT_HASH_SIZE) != 0)) - return 0; // full identity hash is present and does not match + // _lock is NOT locked when this is called + try { + if ((nconf.issuedTo != m_ctx.identity.address()) || (nconf.networkId != m_id)) + return 0; // invalid config that is not for us or not for this network + if ((! Utils::allZero(nconf.issuedToFingerprintHash, ZT_FINGERPRINT_HASH_SIZE)) + && (memcmp(nconf.issuedToFingerprintHash, m_ctx.identity.fingerprint().hash, ZT_FINGERPRINT_HASH_SIZE) + != 0)) + return 0; // full identity hash is present and does not match - if (m_config == nconf) - return 1; // OK config, but duplicate of what we already have + if (m_config == nconf) + return 1; // OK config, but duplicate of what we already have - ZT_VirtualNetworkConfig ctmp; - bool oldPortInitialized; - { // do things that require lock here, but unlock before calling callbacks - Mutex::Lock l1(m_config_l); + ZT_VirtualNetworkConfig ctmp; + bool oldPortInitialized; + { // do things that require lock here, but unlock before calling callbacks + Mutex::Lock l1(m_config_l); - m_config = nconf; - m_lastConfigUpdate = cc.ticks; - _netconfFailure = NETCONF_FAILURE_NONE; + m_config = nconf; + m_lastConfigUpdate = cc.ticks; + _netconfFailure = NETCONF_FAILURE_NONE; - oldPortInitialized = m_portInitialized; - m_portInitialized = true; + oldPortInitialized = m_portInitialized; + m_portInitialized = true; - m_externalConfig(&ctmp); - } + m_externalConfig(&ctmp); + } - m_ctx.cb.virtualNetworkConfigFunction(reinterpret_cast(m_ctx.node), m_ctx.uPtr, cc.tPtr, nconf.networkId, &m_uPtr, (oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); + m_ctx.cb.virtualNetworkConfigFunction( + reinterpret_cast(m_ctx.node), + m_ctx.uPtr, + cc.tPtr, + nconf.networkId, + &m_uPtr, + (oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE + : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, + &ctmp); - if (saveToDisk) { - try { - Dictionary d; - if (nconf.toDictionary(d)) { - uint64_t tmp[2]; - tmp[0] = m_id; - tmp[1] = 0; - Vector< uint8_t > d2; - d.encode(d2); - m_ctx.store->put(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1, d2.data(), (unsigned int)d2.size()); - } - } catch (...) {} - } + if (saveToDisk) { + try { + Dictionary d; + if (nconf.toDictionary(d)) { + uint64_t tmp[2]; + tmp[0] = m_id; + tmp[1] = 0; + Vector d2; + d.encode(d2); + m_ctx.store->put(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1, d2.data(), (unsigned int)d2.size()); + } + } + catch (...) { + } + } - return 2; // OK and configuration has changed - } catch (...) {} // ignore invalid configs - return 0; + return 2; // OK and configuration has changed + } + catch (...) { + } // ignore invalid configs + return 0; } -bool Network::gate(void *tPtr, const SharedPtr< Peer > &peer) noexcept +bool Network::gate(void* tPtr, const SharedPtr& peer) noexcept { - Mutex::Lock lc(m_config_l); + Mutex::Lock lc(m_config_l); - if (!m_config) - return false; - if (m_config.isPublic()) - return true; + if (! m_config) + return false; + if (m_config.isPublic()) + return true; - try { - Mutex::Lock l(m_memberships_l); - return m_memberships[peer->address()].certificateOfMembershipAgress(m_config.com, peer->identity()); - } catch (...) {} + try { + Mutex::Lock l(m_memberships_l); + return m_memberships[peer->address()].certificateOfMembershipAgress(m_config.com, peer->identity()); + } + catch (...) { + } - return false; + return false; } -void Network::doPeriodicTasks(const CallContext &cc) +void Network::doPeriodicTasks(const CallContext& cc) { - if (m_destroyed) - return; + if (m_destroyed) + return; - if ((cc.ticks - m_lastConfigUpdate) >= ZT_NETWORK_AUTOCONF_DELAY) - m_requestConfiguration(cc); + if ((cc.ticks - m_lastConfigUpdate) >= ZT_NETWORK_AUTOCONF_DELAY) + m_requestConfiguration(cc); - { - Mutex::Lock l1(m_memberships_l); + { + Mutex::Lock l1(m_memberships_l); - for (Map< Address, Member >::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) - i->second.clean(m_config); + for (Map::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) + i->second.clean(m_config); - { - Mutex::Lock l2(m_myMulticastGroups_l); + { + Mutex::Lock l2(m_myMulticastGroups_l); - // TODO - /* - Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe); - MulticastGroup *mg = (MulticastGroup *)0; - uint64_t *ts = (uint64_t *)0; - while (i.next(mg,ts)) { - if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) - _multicastGroupsBehindMe.erase(*mg); - } + // TODO + /* + Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe); + MulticastGroup *mg = (MulticastGroup *)0; + uint64_t *ts = (uint64_t *)0; + while (i.next(mg,ts)) { + if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) + _multicastGroupsBehindMe.erase(*mg); + } - _announceMulticastGroups(tPtr,false); - */ - } - } + _announceMulticastGroups(tPtr,false); + */ + } + } } -void Network::learnBridgeRoute(const MAC &mac, const Address &addr) +void Network::learnBridgeRoute(const MAC& mac, const Address& addr) { - Mutex::Lock _l(m_remoteBridgeRoutes_l); - m_remoteBridgeRoutes[mac] = addr; + Mutex::Lock _l(m_remoteBridgeRoutes_l); + m_remoteBridgeRoutes[mac] = addr; - // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes - while (m_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { - Map< Address, unsigned long > counts; - Address maxAddr; - unsigned long maxCount = 0; + // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes + while (m_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { + Map counts; + Address maxAddr; + unsigned long maxCount = 0; - // Find the address responsible for the most entries - for (Map< MAC, Address >::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end(); ++i) { - const unsigned long c = ++counts[i->second]; - if (c > maxCount) { - maxCount = c; - maxAddr = i->second; - } - } + // Find the address responsible for the most entries + for (Map::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end(); ++i) { + const unsigned long c = ++counts[i->second]; + if (c > maxCount) { + maxCount = c; + maxAddr = i->second; + } + } - // Kill this address from our table, since it's most likely spamming us - for (Map< MAC, Address >::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end();) { - if (i->second == maxAddr) - m_remoteBridgeRoutes.erase(i++); - else ++i; - } - } + // Kill this address from our table, since it's most likely spamming us + for (Map::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end();) { + if (i->second == maxAddr) + m_remoteBridgeRoutes.erase(i++); + else + ++i; + } + } } -Member::AddCredentialResult Network::addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const MembershipCredential &com) +Member::AddCredentialResult +Network::addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const MembershipCredential& com) { - if (com.networkId() != m_id) - return Member::ADD_REJECTED; - Mutex::Lock _l(m_memberships_l); - return m_memberships[com.issuedTo().address].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, com); + if (com.networkId() != m_id) + return Member::ADD_REJECTED; + Mutex::Lock _l(m_memberships_l); + return m_memberships[com.issuedTo().address].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, com); } -Member::AddCredentialResult Network::addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const CapabilityCredential &cap) +Member::AddCredentialResult +Network::addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const CapabilityCredential& cap) { - if (cap.networkId() != m_id) - return Member::ADD_REJECTED; - Mutex::Lock _l(m_memberships_l); - return m_memberships[cap.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, cap); + if (cap.networkId() != m_id) + return Member::ADD_REJECTED; + Mutex::Lock _l(m_memberships_l); + return m_memberships[cap.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, cap); } -Member::AddCredentialResult Network::addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const TagCredential &tag) +Member::AddCredentialResult +Network::addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const TagCredential& tag) { - if (tag.networkId() != m_id) - return Member::ADD_REJECTED; - Mutex::Lock _l(m_memberships_l); - return m_memberships[tag.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, tag); + if (tag.networkId() != m_id) + return Member::ADD_REJECTED; + Mutex::Lock _l(m_memberships_l); + return m_memberships[tag.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, tag); } -Member::AddCredentialResult Network::addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const RevocationCredential &rev) +Member::AddCredentialResult +Network::addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const RevocationCredential& rev) { - if (rev.networkId() != m_id) - return Member::ADD_REJECTED; + if (rev.networkId() != m_id) + return Member::ADD_REJECTED; - Mutex::Lock l1(m_memberships_l); - Member &m = m_memberships[rev.target()]; + Mutex::Lock l1(m_memberships_l); + Member& m = m_memberships[rev.target()]; - const Member::AddCredentialResult result = m.addCredential(m_ctx, cc, sourcePeerIdentity, m_config, rev); + const Member::AddCredentialResult result = m.addCredential(m_ctx, cc, sourcePeerIdentity, m_config, rev); - if ((result == Member::ADD_ACCEPTED_NEW) && (rev.fastPropagate())) { - // TODO - /* - Address *a = nullptr; - Membership *m = nullptr; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) { - Packet outp(*a,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); // no COM - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)1); // one revocation! - rev.serialize(outp); - outp.append((uint16_t)0); // no certificates of ownership - m_ctx.sw->send(tPtr,outp,true); - } - } - */ - } + if ((result == Member::ADD_ACCEPTED_NEW) && (rev.fastPropagate())) { + // TODO + /* + Address *a = nullptr; + Membership *m = nullptr; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) { + Packet outp(*a,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + outp.append((uint8_t)0x00); // no COM + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)1); // one revocation! + rev.serialize(outp); + outp.append((uint16_t)0); // no certificates of ownership + m_ctx.sw->send(tPtr,outp,true); + } + } + */ + } - return result; + return result; } -Member::AddCredentialResult Network::addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const OwnershipCredential &coo) +Member::AddCredentialResult +Network::addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const OwnershipCredential& coo) { - if (coo.networkId() != m_id) - return Member::ADD_REJECTED; - Mutex::Lock _l(m_memberships_l); - return m_memberships[coo.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, coo); + if (coo.networkId() != m_id) + return Member::ADD_REJECTED; + Mutex::Lock _l(m_memberships_l); + return m_memberships[coo.issuedTo()].addCredential(m_ctx, cc, sourcePeerIdentity, m_config, coo); } -void Network::pushCredentials(const CallContext &cc, const SharedPtr< Peer > &to) +void Network::pushCredentials(const CallContext& cc, const SharedPtr& to) { - const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta()); - Mutex::Lock _l(m_memberships_l); - Member &m = m_memberships[to->address()]; - if (((cc.ticks - m.lastPushedCredentials()) + 5000) >= tout) - m.pushCredentials(m_ctx, cc, to, m_config); + const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta()); + Mutex::Lock _l(m_memberships_l); + Member& m = m_memberships[to->address()]; + if (((cc.ticks - m.lastPushedCredentials()) + 5000) >= tout) + m.pushCredentials(m_ctx, cc, to, m_config); } void Network::destroy() { - m_memberships_l.lock(); - m_config_l.lock(); - m_destroyed = true; - m_config_l.unlock(); - m_memberships_l.unlock(); + m_memberships_l.lock(); + m_config_l.lock(); + m_destroyed = true; + m_config_l.unlock(); + m_memberships_l.unlock(); } -void Network::externalConfig(ZT_VirtualNetworkConfig *ec) const +void Network::externalConfig(ZT_VirtualNetworkConfig* ec) const { - Mutex::Lock _l(m_config_l); - m_externalConfig(ec); + Mutex::Lock _l(m_config_l); + m_externalConfig(ec); } -void Network::m_requestConfiguration(const CallContext &cc) +void Network::m_requestConfiguration(const CallContext& cc) { - if (m_destroyed) - return; + if (m_destroyed) + return; - if ((m_id >> 56U) == 0xff) { - if ((m_id & 0xffffffU) == 0) { - const uint16_t startPortRange = (uint16_t)((m_id >> 40U) & 0xffff); - const uint16_t endPortRange = (uint16_t)((m_id >> 24U) & 0xffff); - if (endPortRange >= startPortRange) { - ScopedPtr< NetworkConfig > nconf(new NetworkConfig()); + if ((m_id >> 56U) == 0xff) { + if ((m_id & 0xffffffU) == 0) { + const uint16_t startPortRange = (uint16_t)((m_id >> 40U) & 0xffff); + const uint16_t endPortRange = (uint16_t)((m_id >> 24U) & 0xffff); + if (endPortRange >= startPortRange) { + ScopedPtr nconf(new NetworkConfig()); - nconf->networkId = m_id; - nconf->timestamp = (cc.clock < 0) ? cc.ticks : cc.clock; - nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - nconf->revision = 1; - nconf->issuedTo = m_ctx.identity.address(); - nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - nconf->mtu = ZT_DEFAULT_MTU; - nconf->multicastLimit = 0; - nconf->staticIpCount = 1; - nconf->ruleCount = 14; - nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, m_ctx.identity.address().toInt()); + nconf->networkId = m_id; + nconf->timestamp = (cc.clock < 0) ? cc.ticks : cc.clock; + nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + nconf->revision = 1; + nconf->issuedTo = m_ctx.identity.address(); + nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + nconf->mtu = ZT_DEFAULT_MTU; + nconf->multicastLimit = 0; + nconf->staticIpCount = 1; + nconf->ruleCount = 14; + nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, m_ctx.identity.address().toInt()); - // Drop everything but IPv6 - nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80U; // NOT - nconf->rules[0].v.etherType = 0x86dd; // IPv6 - nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; + // Drop everything but IPv6 + nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80U; // NOT + nconf->rules[0].v.etherType = 0x86dd; // IPv6 + nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - // Allow ICMPv6 - nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6 - nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow ICMPv6 + nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; + nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6 + nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Allow destination ports within range - nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[4].v.ipProtocol = 0x11; // UDP - nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40U; // OR - nconf->rules[5].v.ipProtocol = 0x06; // TCP - nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; - nconf->rules[6].v.port[0] = startPortRange; - nconf->rules[6].v.port[1] = endPortRange; - nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow destination ports within range + nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; + nconf->rules[4].v.ipProtocol = 0x11; // UDP + nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40U; // OR + nconf->rules[5].v.ipProtocol = 0x06; // TCP + nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; + nconf->rules[6].v.port[0] = startPortRange; + nconf->rules[6].v.port[1] = endPortRange; + nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Allow non-SYN TCP packets to permit non-connection-initiating traffic - nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80U; // NOT - nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow non-SYN TCP packets to permit non-connection-initiating traffic + nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80U; // NOT + nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; + nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Also allow SYN+ACK which are replies to SYN - nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK; - nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Also allow SYN+ACK which are replies to SYN + nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; + nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; + nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; + nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK; + nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; + nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - nconf->type = ZT_NETWORK_TYPE_PUBLIC; + nconf->type = ZT_NETWORK_TYPE_PUBLIC; - nconf->name[0] = 'a'; - nconf->name[1] = 'd'; - nconf->name[2] = 'h'; - nconf->name[3] = 'o'; - nconf->name[4] = 'c'; - nconf->name[5] = '-'; - Utils::hex((uint16_t)startPortRange, nconf->name + 6); - nconf->name[10] = '-'; - Utils::hex((uint16_t)endPortRange, nconf->name + 11); - nconf->name[15] = (char)0; + nconf->name[0] = 'a'; + nconf->name[1] = 'd'; + nconf->name[2] = 'h'; + nconf->name[3] = 'o'; + nconf->name[4] = 'c'; + nconf->name[5] = '-'; + Utils::hex((uint16_t)startPortRange, nconf->name + 6); + nconf->name[10] = '-'; + Utils::hex((uint16_t)endPortRange, nconf->name + 11); + nconf->name[15] = (char)0; - this->setConfiguration(cc, *nconf, false); - } else { - this->setNotFound(); - } - } else if ((m_id & 0xffU) == 0x01) { - // ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication - const uint64_t myAddress = m_ctx.identity.address().toInt(); - const uint64_t networkHub = (m_id >> 8U) & 0xffffffffffULL; + this->setConfiguration(cc, *nconf, false); + } + else { + this->setNotFound(); + } + } + else if ((m_id & 0xffU) == 0x01) { + // ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather + // and replication + const uint64_t myAddress = m_ctx.identity.address().toInt(); + const uint64_t networkHub = (m_id >> 8U) & 0xffffffffffULL; - uint8_t ipv4[4]; - ipv4[0] = (uint8_t)(m_id >> 48U); - ipv4[1] = (uint8_t)(myAddress >> 16U); - ipv4[2] = (uint8_t)(myAddress >> 8U); - ipv4[3] = (uint8_t)myAddress; + uint8_t ipv4[4]; + ipv4[0] = (uint8_t)(m_id >> 48U); + ipv4[1] = (uint8_t)(myAddress >> 16U); + ipv4[2] = (uint8_t)(myAddress >> 8U); + ipv4[3] = (uint8_t)myAddress; - char v4ascii[24]; - Utils::decimal(ipv4[0], v4ascii); + char v4ascii[24]; + Utils::decimal(ipv4[0], v4ascii); - ScopedPtr< NetworkConfig > nconf(new NetworkConfig()); + ScopedPtr nconf(new NetworkConfig()); - nconf->networkId = m_id; - nconf->timestamp = (cc.clock < 0) ? cc.ticks : cc.clock; - nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - nconf->revision = 1; - nconf->issuedTo = m_ctx.identity.address(); - nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - nconf->mtu = ZT_DEFAULT_MTU; - nconf->multicastLimit = 1024; - nconf->specialistCount = (networkHub == 0) ? 0 : 1; - nconf->staticIpCount = 2; - nconf->ruleCount = 1; + nconf->networkId = m_id; + nconf->timestamp = (cc.clock < 0) ? cc.ticks : cc.clock; + nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + nconf->revision = 1; + nconf->issuedTo = m_ctx.identity.address(); + nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + nconf->mtu = ZT_DEFAULT_MTU; + nconf->multicastLimit = 1024; + nconf->specialistCount = (networkHub == 0) ? 0 : 1; + nconf->staticIpCount = 2; + nconf->ruleCount = 1; - if (networkHub != 0) - nconf->specialists[0] = networkHub; + if (networkHub != 0) + nconf->specialists[0] = networkHub; - nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, myAddress); - nconf->staticIps[1].set(ipv4, 4, 8); + nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, myAddress); + nconf->staticIps[1].set(ipv4, 4, 8); - nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - nconf->type = ZT_NETWORK_TYPE_PUBLIC; + nconf->type = ZT_NETWORK_TYPE_PUBLIC; - nconf->name[0] = 'a'; - nconf->name[1] = 'd'; - nconf->name[2] = 'h'; - nconf->name[3] = 'o'; - nconf->name[4] = 'c'; - nconf->name[5] = '-'; - unsigned long nn = 6; - while ((nconf->name[nn] = v4ascii[nn - 6])) ++nn; - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn] = (char)0; + nconf->name[0] = 'a'; + nconf->name[1] = 'd'; + nconf->name[2] = 'h'; + nconf->name[3] = 'o'; + nconf->name[4] = 'c'; + nconf->name[5] = '-'; + unsigned long nn = 6; + while ((nconf->name[nn] = v4ascii[nn - 6])) + ++nn; + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn] = (char)0; - this->setConfiguration(cc, *nconf, false); - } - return; - } + this->setConfiguration(cc, *nconf, false); + } + return; + } - const Address ctrl(controller()); + const Address ctrl(controller()); - Dictionary rmd; - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR, (uint64_t)1); // 1 == ZeroTier, no other vendors at the moment - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION, (uint64_t)ZT_PROTO_VERSION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION, (uint64_t)ZEROTIER_VERSION_MAJOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION, (uint64_t)ZEROTIER_VERSION_MINOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION, (uint64_t)ZEROTIER_VERSION_REVISION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES, (uint64_t)ZT_MAX_NETWORK_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES, (uint64_t)ZT_MAX_NETWORK_CAPABILITIES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES, (uint64_t)ZT_MAX_CAPABILITY_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS, (uint64_t)ZT_MAX_NETWORK_TAGS); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS, (uint64_t)0); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV, (uint64_t)ZT_RULES_ENGINE_REVISION); + Dictionary rmd; + rmd.add( + ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR, + (uint64_t)1); // 1 == ZeroTier, no other vendors at the moment + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION, (uint64_t)ZT_PROTO_VERSION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION, (uint64_t)ZEROTIER_VERSION_MAJOR); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION, (uint64_t)ZEROTIER_VERSION_MINOR); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION, (uint64_t)ZEROTIER_VERSION_REVISION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES, (uint64_t)ZT_MAX_NETWORK_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES, (uint64_t)ZT_MAX_NETWORK_CAPABILITIES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES, (uint64_t)ZT_MAX_CAPABILITY_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS, (uint64_t)ZT_MAX_NETWORK_TAGS); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS, (uint64_t)0); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV, (uint64_t)ZT_RULES_ENGINE_REVISION); - m_ctx.t->networkConfigRequestSent(cc, 0x335bb1a2, m_id); + m_ctx.t->networkConfigRequestSent(cc, 0x335bb1a2, m_id); - if (ctrl == m_ctx.identity.address()) { - if (m_ctx.localNetworkController) { - m_ctx.localNetworkController->request(m_id, InetAddress(), 0xffffffffffffffffULL, m_ctx.identity, rmd); - } else { - this->setNotFound(); - } - return; - } + if (ctrl == m_ctx.identity.address()) { + if (m_ctx.localNetworkController) { + m_ctx.localNetworkController->request(m_id, InetAddress(), 0xffffffffffffffffULL, m_ctx.identity, rmd); + } + else { + this->setNotFound(); + } + return; + } - // TODO - /* - Packet outp(ctrl,m_ctx.identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append((uint64_t)_id); - const unsigned int rmdSize = rmd->sizeBytes(); - outp.append((uint16_t)rmdSize); - outp.append((const void *)rmd->data(),rmdSize); - if (_config) { - outp.append((uint64_t)_config.revision); - outp.append((uint64_t)_config.timestamp); - } else { - outp.append((unsigned char)0,16); - } - outp.compress(); - m_ctx.node->expectReplyTo(outp.packetId()); - m_ctx.sw->send(tPtr,outp,true); - */ + // TODO + /* + Packet outp(ctrl,m_ctx.identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append((uint64_t)_id); + const unsigned int rmdSize = rmd->sizeBytes(); + outp.append((uint16_t)rmdSize); + outp.append((const void *)rmd->data(),rmdSize); + if (_config) { + outp.append((uint64_t)_config.revision); + outp.append((uint64_t)_config.timestamp); + } else { + outp.append((unsigned char)0,16); + } + outp.compress(); + m_ctx.node->expectReplyTo(outp.packetId()); + m_ctx.sw->send(tPtr,outp,true); + */ } ZT_VirtualNetworkStatus Network::m_status() const { - switch (_netconfFailure) { - case NETCONF_FAILURE_ACCESS_DENIED: - return ZT_NETWORK_STATUS_ACCESS_DENIED; - case NETCONF_FAILURE_NOT_FOUND: - return ZT_NETWORK_STATUS_NOT_FOUND; - case NETCONF_FAILURE_NONE: - return ((m_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION); - default: - return ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION; - } + switch (_netconfFailure) { + case NETCONF_FAILURE_ACCESS_DENIED: + return ZT_NETWORK_STATUS_ACCESS_DENIED; + case NETCONF_FAILURE_NOT_FOUND: + return ZT_NETWORK_STATUS_NOT_FOUND; + case NETCONF_FAILURE_NONE: + return ((m_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION); + default: + return ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION; + } } -void Network::m_externalConfig(ZT_VirtualNetworkConfig *ec) const +void Network::m_externalConfig(ZT_VirtualNetworkConfig* ec) const { - // assumes _config_l is locked - ec->nwid = m_id; - ec->mac = m_mac.toInt(); - if (m_config) - Utils::scopy(ec->name, sizeof(ec->name), m_config.name); - else ec->name[0] = (char)0; - ec->status = m_status(); - ec->type = (m_config) ? (m_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; - ec->mtu = (m_config) ? m_config.mtu : ZT_DEFAULT_MTU; - Vector< Address > ab; - for (unsigned int i = 0; i < m_config.specialistCount; ++i) { - if ((m_config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) - ab.push_back(Address(m_config.specialists[i])); - } - ec->bridge = (std::find(ab.begin(), ab.end(), m_ctx.identity.address()) != ab.end()) ? 1 : 0; - ec->broadcastEnabled = (m_config) ? (m_config.enableBroadcast() ? 1 : 0) : 0; - ec->netconfRevision = (m_config) ? (unsigned long)m_config.revision : 0; + // assumes _config_l is locked + ec->nwid = m_id; + ec->mac = m_mac.toInt(); + if (m_config) + Utils::scopy(ec->name, sizeof(ec->name), m_config.name); + else + ec->name[0] = (char)0; + ec->status = m_status(); + ec->type = (m_config) ? (m_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) + : ZT_NETWORK_TYPE_PRIVATE; + ec->mtu = (m_config) ? m_config.mtu : ZT_DEFAULT_MTU; + Vector
ab; + for (unsigned int i = 0; i < m_config.specialistCount; ++i) { + if ((m_config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) + ab.push_back(Address(m_config.specialists[i])); + } + ec->bridge = (std::find(ab.begin(), ab.end(), m_ctx.identity.address()) != ab.end()) ? 1 : 0; + ec->broadcastEnabled = (m_config) ? (m_config.enableBroadcast() ? 1 : 0) : 0; + ec->netconfRevision = (m_config) ? (unsigned long)m_config.revision : 0; - ec->assignedAddressCount = 0; - for (unsigned int i = 0; i < ZT_MAX_ZT_ASSIGNED_ADDRESSES; ++i) { - if (i < m_config.staticIpCount) { - Utils::copy< sizeof(struct sockaddr_storage) >(&(ec->assignedAddresses[i]), &(m_config.staticIps[i])); - ++ec->assignedAddressCount; - } else { - Utils::zero< sizeof(struct sockaddr_storage) >(&(ec->assignedAddresses[i])); - } - } + ec->assignedAddressCount = 0; + for (unsigned int i = 0; i < ZT_MAX_ZT_ASSIGNED_ADDRESSES; ++i) { + if (i < m_config.staticIpCount) { + Utils::copy(&(ec->assignedAddresses[i]), &(m_config.staticIps[i])); + ++ec->assignedAddressCount; + } + else { + Utils::zero(&(ec->assignedAddresses[i])); + } + } - ec->routeCount = 0; - for (unsigned int i = 0; i < ZT_MAX_NETWORK_ROUTES; ++i) { - if (i < m_config.routeCount) { - Utils::copy< sizeof(ZT_VirtualNetworkRoute) >(&(ec->routes[i]), &(m_config.routes[i])); - ++ec->routeCount; - } else { - Utils::zero< sizeof(ZT_VirtualNetworkRoute) >(&(ec->routes[i])); - } - } + ec->routeCount = 0; + for (unsigned int i = 0; i < ZT_MAX_NETWORK_ROUTES; ++i) { + if (i < m_config.routeCount) { + Utils::copy(&(ec->routes[i]), &(m_config.routes[i])); + ++ec->routeCount; + } + else { + Utils::zero(&(ec->routes[i])); + } + } } -void Network::m_announceMulticastGroups(void *tPtr, bool force) +void Network::m_announceMulticastGroups(void* tPtr, bool force) { - // Assumes _myMulticastGroups_l and _memberships_l are locked - const Vector< MulticastGroup > groups(m_allMulticastGroups()); - m_announceMulticastGroupsTo(tPtr, controller(), groups); + // Assumes _myMulticastGroups_l and _memberships_l are locked + const Vector groups(m_allMulticastGroups()); + m_announceMulticastGroupsTo(tPtr, controller(), groups); - // TODO - /* + // TODO + /* Address *a = nullptr; Membership *m = nullptr; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time - if ((!announce)&&(force)) - announce = true; - if ((announce)&&(m->isAllowedOnNetwork(_config))) - _announceMulticastGroupsTo(tPtr,*a,groups); - } - */ - + bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last +push time if ((!announce)&&(force)) announce = true; if ((announce)&&(m->isAllowedOnNetwork(_config))) + _announceMulticastGroupsTo(tPtr,*a,groups); + } + */ } -void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector< MulticastGroup > &allMulticastGroups) +void Network::m_announceMulticastGroupsTo( + void* tPtr, + const Address& peer, + const Vector& allMulticastGroups) { #if 0 // Assumes _myMulticastGroups_l and _memberships_l are locked @@ -1529,19 +1817,21 @@ void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const #endif } -Vector< MulticastGroup > Network::m_allMulticastGroups() const +Vector Network::m_allMulticastGroups() const { - // Assumes _myMulticastGroups_l is locked - Vector< MulticastGroup > mgs; - mgs.reserve(m_myMulticastGroups.size() + m_multicastGroupsBehindMe.size() + 1); - mgs.insert(mgs.end(), m_myMulticastGroups.begin(), m_myMulticastGroups.end()); - for (Map< MulticastGroup, int64_t >::const_iterator i(m_multicastGroupsBehindMe.begin()); i != m_multicastGroupsBehindMe.end(); ++i) - mgs.push_back(i->first); - if ((m_config) && (m_config.enableBroadcast())) - mgs.push_back(Network::BROADCAST); - std::sort(mgs.begin(), mgs.end()); - mgs.erase(std::unique(mgs.begin(), mgs.end()), mgs.end()); - return mgs; + // Assumes _myMulticastGroups_l is locked + Vector mgs; + mgs.reserve(m_myMulticastGroups.size() + m_multicastGroupsBehindMe.size() + 1); + mgs.insert(mgs.end(), m_myMulticastGroups.begin(), m_myMulticastGroups.end()); + for (Map::const_iterator i(m_multicastGroupsBehindMe.begin()); + i != m_multicastGroupsBehindMe.end(); + ++i) + mgs.push_back(i->first); + if ((m_config) && (m_config.enableBroadcast())) + mgs.push_back(Network::BROADCAST); + std::sort(mgs.begin(), mgs.end()); + mgs.erase(std::unique(mgs.begin(), mgs.end()), mgs.end()); + return mgs; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Network.hpp b/core/Network.hpp index 274d07236..8d2efbba9 100644 --- a/core/Network.hpp +++ b/core/Network.hpp @@ -14,19 +14,19 @@ #ifndef ZT_NETWORK_HPP #define ZT_NETWORK_HPP -#include "Constants.hpp" #include "Address.hpp" -#include "Mutex.hpp" -#include "SharedPtr.hpp" -#include "MulticastGroup.hpp" -#include "MAC.hpp" #include "Buf.hpp" -#include "Dictionary.hpp" -#include "Member.hpp" -#include "NetworkConfig.hpp" -#include "MembershipCredential.hpp" -#include "Containers.hpp" #include "CallContext.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Dictionary.hpp" +#include "MAC.hpp" +#include "Member.hpp" +#include "MembershipCredential.hpp" +#include "MulticastGroup.hpp" +#include "Mutex.hpp" +#include "NetworkConfig.hpp" +#include "SharedPtr.hpp" #define ZT_NETWORK_MAX_INCOMING_UPDATES 3 @@ -39,349 +39,375 @@ class Peer; /** * A virtual LAN */ -class Network -{ - friend class SharedPtr< Network >; +class Network { + friend class SharedPtr; -public: - /** - * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 - */ - static const MulticastGroup BROADCAST; + public: + /** + * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 + */ + static const MulticastGroup BROADCAST; - /** - * Compute primary controller device ID from network ID - */ - static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept - { return Address(nwid >> 24U); } + /** + * Compute primary controller device ID from network ID + */ + static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept + { + return Address(nwid >> 24U); + } - /** - * Construct a new network - * - * Note that init() should be called immediately after the network is - * constructed to actually configure the port. - * - * @param nwid Network ID - * @param controllerFingerprint Initial controller fingerprint if non-NULL - * @param uptr Arbitrary pointer used by externally-facing API (for user use) - * @param nconf Network config, if known - */ - Network( - const Context &ctx, - const CallContext &cc, - uint64_t nwid, - const Fingerprint &controllerFingerprint, - void *uptr, - const NetworkConfig *nconf); + /** + * Construct a new network + * + * Note that init() should be called immediately after the network is + * constructed to actually configure the port. + * + * @param nwid Network ID + * @param controllerFingerprint Initial controller fingerprint if non-NULL + * @param uptr Arbitrary pointer used by externally-facing API (for user use) + * @param nconf Network config, if known + */ + Network( + const Context& ctx, + const CallContext& cc, + uint64_t nwid, + const Fingerprint& controllerFingerprint, + void* uptr, + const NetworkConfig* nconf); - ~Network(); + ~Network(); - ZT_INLINE uint64_t id() const noexcept - { return m_id; } + ZT_INLINE uint64_t id() const noexcept + { + return m_id; + } - ZT_INLINE Address controller() const noexcept - { return Address(m_id >> 24U); } + ZT_INLINE Address controller() const noexcept + { + return Address(m_id >> 24U); + } - ZT_INLINE bool multicastEnabled() const noexcept - { return (m_config.multicastLimit > 0); } + ZT_INLINE bool multicastEnabled() const noexcept + { + return (m_config.multicastLimit > 0); + } - ZT_INLINE bool hasConfig() const noexcept - { return (m_config); } + ZT_INLINE bool hasConfig() const noexcept + { + return (m_config); + } - ZT_INLINE uint64_t lastConfigUpdate() const noexcept - { return m_lastConfigUpdate; } + ZT_INLINE uint64_t lastConfigUpdate() const noexcept + { + return m_lastConfigUpdate; + } - ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept - { return m_status(); } + ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept + { + return m_status(); + } - ZT_INLINE const NetworkConfig &config() const noexcept - { return m_config; } + ZT_INLINE const NetworkConfig& config() const noexcept + { + return m_config; + } - ZT_INLINE const MAC &mac() const noexcept - { return m_mac; } + ZT_INLINE const MAC& mac() const noexcept + { + return m_mac; + } - /** - * Apply filters to an outgoing packet - * - * This applies filters from our network config and, if that doesn't match, - * our capabilities in ascending order of capability ID. Additional actions - * such as TEE may be taken, and credentials may be pushed, so this is not - * side-effect-free. It's basically step one in sending something over VL2. - * - * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) - * @param ztSource Source ZeroTier address - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return True if packet should be sent, false if dropped or redirected - */ - bool filterOutgoingPacket( - const CallContext &cc, - bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - unsigned int frameLen, - unsigned int etherType, - unsigned int vlanId, - uint8_t &qosBucket); + /** + * Apply filters to an outgoing packet + * + * This applies filters from our network config and, if that doesn't match, + * our capabilities in ascending order of capability ID. Additional actions + * such as TEE may be taken, and credentials may be pushed, so this is not + * side-effect-free. It's basically step one in sending something over VL2. + * + * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) + * @param ztSource Source ZeroTier address + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return True if packet should be sent, false if dropped or redirected + */ + bool filterOutgoingPacket( + const CallContext& cc, + bool noTee, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + unsigned int frameLen, + unsigned int etherType, + unsigned int vlanId, + uint8_t& qosBucket); - /** - * Apply filters to an incoming packet - * - * This applies filters from our network config and, if that doesn't match, - * the peer's capabilities in ascending order of capability ID. If there is - * a match certain actions may be taken such as sending a copy of the packet - * to a TEE or REDIRECT target. - * - * @param sourcePeer Source Peer - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return 0 == drop, 1 == accept, 2 == accept even if bridged - */ - int filterIncomingPacket( - const CallContext &cc, - const SharedPtr< Peer > &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - unsigned int frameLen, - unsigned int etherType, - unsigned int vlanId); + /** + * Apply filters to an incoming packet + * + * This applies filters from our network config and, if that doesn't match, + * the peer's capabilities in ascending order of capability ID. If there is + * a match certain actions may be taken such as sending a copy of the packet + * to a TEE or REDIRECT target. + * + * @param sourcePeer Source Peer + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return 0 == drop, 1 == accept, 2 == accept even if bridged + */ + int filterIncomingPacket( + const CallContext& cc, + const SharedPtr& sourcePeer, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + unsigned int frameLen, + unsigned int etherType, + unsigned int vlanId); - /** - * Subscribe to a multicast group - * - * @param mg New multicast group - */ - void multicastSubscribe(const CallContext &cc, const MulticastGroup &mg); + /** + * Subscribe to a multicast group + * + * @param mg New multicast group + */ + void multicastSubscribe(const CallContext& cc, const MulticastGroup& mg); - /** - * Unsubscribe from a multicast group - * - * @param mg Multicast group - */ - void multicastUnsubscribe(const MulticastGroup &mg); + /** + * Unsubscribe from a multicast group + * + * @param mg Multicast group + */ + void multicastUnsubscribe(const MulticastGroup& mg); - /** - * Parse, verify, and handle an inbound network config chunk - * - * This is called from IncomingPacket to handle incoming network config - * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It's a common - * bit of packet parsing code that also verifies chunks and replicates - * them (via rumor mill flooding) if their fast propagate flag is set. - * - * @param packetId Packet ID or 0 if none (e.g. via cluster path) - * @param source Peer that actually sent this chunk (probably controller) - * @param chunk Buffer containing chunk - * @param ptr Index of chunk and related fields in packet (starting with network ID) - * @param size Size of data in chunk buffer (total, not relative to ptr) - * @return Update ID if update was fully assembled and accepted or 0 otherwise - */ - uint64_t handleConfigChunk( - const CallContext &cc, - uint64_t packetId, - const SharedPtr< Peer > &source, - const Buf &chunk, - int ptr, - int size); + /** + * Parse, verify, and handle an inbound network config chunk + * + * This is called from IncomingPacket to handle incoming network config + * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It's a common + * bit of packet parsing code that also verifies chunks and replicates + * them (via rumor mill flooding) if their fast propagate flag is set. + * + * @param packetId Packet ID or 0 if none (e.g. via cluster path) + * @param source Peer that actually sent this chunk (probably controller) + * @param chunk Buffer containing chunk + * @param ptr Index of chunk and related fields in packet (starting with network ID) + * @param size Size of data in chunk buffer (total, not relative to ptr) + * @return Update ID if update was fully assembled and accepted or 0 otherwise + */ + uint64_t handleConfigChunk( + const CallContext& cc, + uint64_t packetId, + const SharedPtr& source, + const Buf& chunk, + int ptr, + int size); - /** - * Set network configuration - * - * This is normally called internally when a configuration is received - * and fully assembled, but it can also be called on Node startup when - * cached configurations are re-read from the data store. - * - * @param nconf Network configuration - * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. - * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new - */ - int setConfiguration( - const CallContext &cc, - const NetworkConfig &nconf, - bool saveToDisk); + /** + * Set network configuration + * + * This is normally called internally when a configuration is received + * and fully assembled, but it can also be called on Node startup when + * cached configurations are re-read from the data store. + * + * @param nconf Network configuration + * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. + * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new + */ + int setConfiguration(const CallContext& cc, const NetworkConfig& nconf, bool saveToDisk); - /** - * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this - */ - ZT_INLINE void setAccessDenied() noexcept - { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; } + /** + * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this + */ + ZT_INLINE void setAccessDenied() noexcept + { + _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; + } - /** - * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this - */ - ZT_INLINE void setNotFound() noexcept - { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; } + /** + * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this + */ + ZT_INLINE void setNotFound() noexcept + { + _netconfFailure = NETCONF_FAILURE_NOT_FOUND; + } - /** - * Determine whether this peer is permitted to communicate on this network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer Peer to check - */ - bool gate(void *tPtr, const SharedPtr< Peer > &peer) noexcept; + /** + * Determine whether this peer is permitted to communicate on this network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer Peer to check + */ + bool gate(void* tPtr, const SharedPtr& peer) noexcept; - /** - * Do periodic cleanup and housekeeping tasks - */ - void doPeriodicTasks(const CallContext &cc); + /** + * Do periodic cleanup and housekeeping tasks + */ + void doPeriodicTasks(const CallContext& cc); - /** - * Find the node on this network that has this MAC behind it (if any) - * - * @param mac MAC address - * @return ZeroTier address of bridge to this MAC - */ - ZT_INLINE Address findBridgeTo(const MAC &mac) const - { - Mutex::Lock _l(m_remoteBridgeRoutes_l); - Map< MAC, Address >::const_iterator br(m_remoteBridgeRoutes.find(mac)); - return ((br == m_remoteBridgeRoutes.end()) ? Address() : br->second); - } + /** + * Find the node on this network that has this MAC behind it (if any) + * + * @param mac MAC address + * @return ZeroTier address of bridge to this MAC + */ + ZT_INLINE Address findBridgeTo(const MAC& mac) const + { + Mutex::Lock _l(m_remoteBridgeRoutes_l); + Map::const_iterator br(m_remoteBridgeRoutes.find(mac)); + return ((br == m_remoteBridgeRoutes.end()) ? Address() : br->second); + } - /** - * Set a bridge route - * - * @param mac MAC address of destination - * @param addr Bridge this MAC is reachable behind - */ - void learnBridgeRoute(const MAC &mac, const Address &addr); + /** + * Set a bridge route + * + * @param mac MAC address of destination + * @param addr Bridge this MAC is reachable behind + */ + void learnBridgeRoute(const MAC& mac, const Address& addr); - /** - * Learn a multicast group that is bridged to our tap device - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param mg Multicast group - * @param now Current time - */ - ZT_INLINE void learnBridgedMulticastGroup(const MulticastGroup &mg, int64_t now) - { - Mutex::Lock l(m_myMulticastGroups_l); - m_multicastGroupsBehindMe[mg] = now; - } + /** + * Learn a multicast group that is bridged to our tap device + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param mg Multicast group + * @param now Current time + */ + ZT_INLINE void learnBridgedMulticastGroup(const MulticastGroup& mg, int64_t now) + { + Mutex::Lock l(m_myMulticastGroups_l); + m_multicastGroupsBehindMe[mg] = now; + } - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const MembershipCredential &com); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Member::AddCredentialResult + addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const MembershipCredential& com); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const CapabilityCredential &cap); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Member::AddCredentialResult + addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const CapabilityCredential& cap); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const TagCredential &tag); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Member::AddCredentialResult + addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const TagCredential& tag); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const RevocationCredential &rev); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Member::AddCredentialResult + addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const RevocationCredential& rev); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const OwnershipCredential &coo); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Member::AddCredentialResult + addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const OwnershipCredential& coo); - /** - * Push credentials to a peer if timeouts indicate that we should do so - * - * @param to Destination peer - */ - void pushCredentials(const CallContext &cc, const SharedPtr< Peer > &to); + /** + * Push credentials to a peer if timeouts indicate that we should do so + * + * @param to Destination peer + */ + void pushCredentials(const CallContext& cc, const SharedPtr& to); - /** - * Destroy this network - * - * This sets the network to completely remove itself on delete. This also prevents the - * call of the normal port shutdown event on delete. - */ - void destroy(); + /** + * Destroy this network + * + * This sets the network to completely remove itself on delete. This also prevents the + * call of the normal port shutdown event on delete. + */ + void destroy(); - /** - * Get this network's config for export via the ZT core API - * - * @param ec Buffer to fill with externally-visible network configuration - */ - void externalConfig(ZT_VirtualNetworkConfig *ec) const; + /** + * Get this network's config for export via the ZT core API + * + * @param ec Buffer to fill with externally-visible network configuration + */ + void externalConfig(ZT_VirtualNetworkConfig* ec) const; - /** - * Iterate through memberships - * - * @param f Function of (const Address,const Membership) - */ - template< typename F > - ZT_INLINE void eachMember(F f) - { - Mutex::Lock ml(m_memberships_l); - for (Map< Address, Member >::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto) - if (!f(i->first, i->second)) - break; - } - } + /** + * Iterate through memberships + * + * @param f Function of (const Address,const Membership) + */ + template ZT_INLINE void eachMember(F f) + { + Mutex::Lock ml(m_memberships_l); + for (Map::iterator i(m_memberships.begin()); i != m_memberships.end(); + ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto) + if (! f(i->first, i->second)) + break; + } + } - /** - * @return Externally usable pointer-to-pointer exported via the core API - */ - ZT_INLINE void **userPtr() noexcept - { return &m_uPtr; } + /** + * @return Externally usable pointer-to-pointer exported via the core API + */ + ZT_INLINE void** userPtr() noexcept + { + return &m_uPtr; + } -private: - void m_requestConfiguration(const CallContext &cc); - ZT_VirtualNetworkStatus m_status() const; - void m_externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - void m_announceMulticastGroups(void *tPtr, bool force); - void m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector< MulticastGroup > &allMulticastGroups); - Vector< MulticastGroup > m_allMulticastGroups() const; + private: + void m_requestConfiguration(const CallContext& cc); + ZT_VirtualNetworkStatus m_status() const; + void m_externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked + void m_announceMulticastGroups(void* tPtr, bool force); + void m_announceMulticastGroupsTo(void* tPtr, const Address& peer, const Vector& allMulticastGroups); + Vector m_allMulticastGroups() const; - const Context &m_ctx; - void *m_uPtr; - const uint64_t m_id; - Fingerprint m_controllerFingerprint; - MAC m_mac; // local MAC address - bool m_portInitialized; - std::atomic< bool > m_destroyed; + const Context& m_ctx; + void* m_uPtr; + const uint64_t m_id; + Fingerprint m_controllerFingerprint; + MAC m_mac; // local MAC address + bool m_portInitialized; + std::atomic m_destroyed; - Vector< MulticastGroup > m_myMulticastGroups; // multicast groups that we belong to (according to tap) - Map< MulticastGroup, int64_t > m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) - Map< MAC, Address > m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) + Vector m_myMulticastGroups; // multicast groups that we belong to (according to tap) + Map m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we + // last saw them (if we are a bridge) + Map m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices + // behind remote bridges) - NetworkConfig m_config; - std::atomic< int64_t > m_lastConfigUpdate; + NetworkConfig m_config; + std::atomic m_lastConfigUpdate; - volatile enum - { - NETCONF_FAILURE_NONE, - NETCONF_FAILURE_ACCESS_DENIED, - NETCONF_FAILURE_NOT_FOUND, - NETCONF_FAILURE_INIT_FAILED - } _netconfFailure; + volatile enum { + NETCONF_FAILURE_NONE, + NETCONF_FAILURE_ACCESS_DENIED, + NETCONF_FAILURE_NOT_FOUND, + NETCONF_FAILURE_INIT_FAILED + } _netconfFailure; - Map< Address, Member > m_memberships; + Map m_memberships; - Mutex m_myMulticastGroups_l; - Mutex m_remoteBridgeRoutes_l; - Mutex m_config_l; - Mutex m_memberships_l; + Mutex m_myMulticastGroups_l; + Mutex m_remoteBridgeRoutes_l; + Mutex m_config_l; + Mutex m_memberships_l; - std::atomic< int > __refCount; + std::atomic __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/NetworkConfig.cpp b/core/NetworkConfig.cpp index a2e183197..fa32930fb 100644 --- a/core/NetworkConfig.cpp +++ b/core/NetworkConfig.cpp @@ -11,265 +11,293 @@ */ /****/ -#include +#include "NetworkConfig.hpp" + +#include "Buf.hpp" +#include "ScopedPtr.hpp" #include - -#include "NetworkConfig.hpp" -#include "ScopedPtr.hpp" -#include "Buf.hpp" +#include namespace ZeroTier { -bool NetworkConfig::toDictionary(Dictionary &d) const +bool NetworkConfig::toDictionary(Dictionary& d) const { - uint8_t tmp[ZT_BUF_MEM_SIZE]; - try { - d.clear(); + uint8_t tmp[ZT_BUF_MEM_SIZE]; + try { + d.clear(); - d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId); - d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp); - d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta); - d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision); - d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString((char *)tmp)); - d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH,this->issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE); - d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags); - d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit); - d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type); - d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name); - d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu); + d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, this->networkId); + d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, this->timestamp); + d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, this->credentialTimeMaxDelta); + d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION, this->revision); + d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, this->issuedTo.toString((char*)tmp)); + d.add( + ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH, + this->issuedToFingerprintHash, + ZT_FINGERPRINT_HASH_SIZE); + d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, this->flags); + d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, (uint64_t)this->multicastLimit); + d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)this->type); + d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name); + d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU, (uint64_t)this->mtu); - if (this->com) { - d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,tmp,this->com.marshal(tmp)); - } + if (this->com) { + d.add(ZT_NETWORKCONFIG_DICT_KEY_COM, tmp, this->com.marshal(tmp)); + } - Vector *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); - for (unsigned int i = 0; i < this->capabilityCount; ++i) { - int l = this->capabilities[i].marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - } + Vector* blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); + for (unsigned int i = 0; i < this->capabilityCount; ++i) { + int l = this->capabilities[i].marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); - for (unsigned int i = 0; i < this->tagCount; ++i) { - int l = this->tags[i].marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); + for (unsigned int i = 0; i < this->tagCount; ++i) { + int l = this->tags[i].marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); - for (unsigned int i = 0; i < this->certificateOfOwnershipCount; ++i) { - int l = this->certificatesOfOwnership[i].marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); + for (unsigned int i = 0; i < this->certificateOfOwnershipCount; ++i) { + int l = this->certificatesOfOwnership[i].marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); - for (unsigned int i = 0; i < this->specialistCount; ++i) { - Utils::storeBigEndian(tmp,this->specialists[i]); - blob->insert(blob->end(),tmp,tmp + 8); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); + for (unsigned int i = 0; i < this->specialistCount; ++i) { + Utils::storeBigEndian(tmp, this->specialists[i]); + blob->insert(blob->end(), tmp, tmp + 8); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); - for (unsigned int i = 0; i < this->routeCount; ++i) { - int l = asInetAddress(this->routes[i].target).marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - l = asInetAddress(this->routes[i].via).marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); + for (unsigned int i = 0; i < this->routeCount; ++i) { + int l = asInetAddress(this->routes[i].target).marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + l = asInetAddress(this->routes[i].via).marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); - for (unsigned int i = 0; i < this->staticIpCount; ++i) { - int l = this->staticIps[i].marshal(tmp); - if (l < 0) - return false; - blob->insert(blob->end(),tmp,tmp + l); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); + for (unsigned int i = 0; i < this->staticIpCount; ++i) { + int l = this->staticIps[i].marshal(tmp); + if (l < 0) + return false; + blob->insert(blob->end(), tmp, tmp + l); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); - if (this->ruleCount) { - blob->resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX); - int l = CapabilityCredential::marshalVirtualNetworkRules(blob->data(), rules, ruleCount); - if (l > 0) - blob->resize(l); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); + if (this->ruleCount) { + blob->resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX); + int l = CapabilityCredential::marshalVirtualNetworkRules(blob->data(), rules, ruleCount); + if (l > 0) + blob->resize(l); + } - return true; - } catch ( ... ) {} - return false; + return true; + } + catch (...) { + } + return false; } -bool NetworkConfig::fromDictionary(const Dictionary &d) +bool NetworkConfig::fromDictionary(const Dictionary& d) { - static const NetworkConfig NIL_NC; - try { - *this = NIL_NC; + static const NetworkConfig NIL_NC; + try { + *this = NIL_NC; - this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); - if (!this->networkId) - return false; - this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); - if (this->timestamp <= 0) - return false; - this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0); - this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); - this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); - const Vector *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]); - if (blob->size() == ZT_FINGERPRINT_HASH_SIZE) { - Utils::copy(this->issuedToFingerprintHash,blob->data()); - } else { - Utils::zero(this->issuedToFingerprintHash); - } - if (!this->issuedTo) - return false; - this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); - d.getS(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); - this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU); - if (this->mtu < 1280) - this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others - else if (this->mtu > ZT_MAX_MTU) - this->mtu = ZT_MAX_MTU; + this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0); + if (! this->networkId) + return false; + this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0); + if (this->timestamp <= 0) + return false; + this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0); + this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0); + this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0); + const Vector* blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]); + if (blob->size() == ZT_FINGERPRINT_HASH_SIZE) { + Utils::copy(this->issuedToFingerprintHash, blob->data()); + } + else { + Utils::zero(this->issuedToFingerprintHash); + } + if (! this->issuedTo) + return false; + this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0); + d.getS(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name, sizeof(this->name)); + this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU); + if (this->mtu < 1280) + this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others + else if (this->mtu > ZT_MAX_MTU) + this->mtu = ZT_MAX_MTU; - if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { - return false; - } else { - this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); - this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); + if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION, 0) < 6) { + return false; + } + else { + this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, 0); + this->type = + (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)ZT_NETWORK_TYPE_PRIVATE); - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_COM]); - if (!blob->empty()) { - if (this->com.unmarshal(blob->data(),(int)(blob->size()) < 0)) - return false; - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_COM]); + if (! blob->empty()) { + if (this->com.unmarshal(blob->data(), (int)(blob->size()) < 0)) + return false; + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); - if (!blob->empty()) { - try { - unsigned int p = 0; - while (p < blob->size()) { - CapabilityCredential cap; - int l = cap.unmarshal(blob->data() + p,(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - if (this->capabilityCount < ZT_MAX_NETWORK_CAPABILITIES) - this->capabilities[this->capabilityCount++] = cap; - } - } catch ( ... ) {} - std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); + if (! blob->empty()) { + try { + unsigned int p = 0; + while (p < blob->size()) { + CapabilityCredential cap; + int l = cap.unmarshal(blob->data() + p, (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + if (this->capabilityCount < ZT_MAX_NETWORK_CAPABILITIES) + this->capabilities[this->capabilityCount++] = cap; + } + } + catch (...) { + } + std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount])); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); - if (!blob->empty()) { - try { - unsigned int p = 0; - while (p < blob->size()) { - TagCredential tag; - int l = tag.unmarshal(blob->data() + p,(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - if (this->tagCount < ZT_MAX_NETWORK_TAGS) - this->tags[this->tagCount++] = tag; - } - } catch ( ... ) {} - std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); + if (! blob->empty()) { + try { + unsigned int p = 0; + while (p < blob->size()) { + TagCredential tag; + int l = tag.unmarshal(blob->data() + p, (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + if (this->tagCount < ZT_MAX_NETWORK_TAGS) + this->tags[this->tagCount++] = tag; + } + } + catch (...) { + } + std::sort(&(this->tags[0]), &(this->tags[this->tagCount])); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); - if (!blob->empty()) { - try { - unsigned int p = 0; - while (p < blob->size()) { - OwnershipCredential coo; - int l = coo.unmarshal(blob->data() + p,(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - if (this->certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) - this->certificatesOfOwnership[certificateOfOwnershipCount++] = coo; - } - } catch ( ... ) {} - std::sort(&(this->certificatesOfOwnership[0]),&(this->certificatesOfOwnership[this->certificateOfOwnershipCount])); - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); + if (! blob->empty()) { + try { + unsigned int p = 0; + while (p < blob->size()) { + OwnershipCredential coo; + int l = coo.unmarshal(blob->data() + p, (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + if (this->certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) + this->certificatesOfOwnership[certificateOfOwnershipCount++] = coo; + } + } + catch (...) { + } + std::sort( + &(this->certificatesOfOwnership[0]), + &(this->certificatesOfOwnership[this->certificateOfOwnershipCount])); + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); - if (!blob->empty()) { - unsigned int p = 0; - while (((p + 8) <= blob->size())&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { - this->specialists[this->specialistCount++] = Utils::loadBigEndian(blob->data() + p); - p += 8; - } - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); + if (! blob->empty()) { + unsigned int p = 0; + while (((p + 8) <= blob->size()) && (specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { + this->specialists[this->specialistCount++] = Utils::loadBigEndian(blob->data() + p); + p += 8; + } + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); - if (!blob->empty()) { - unsigned int p = 0; - while ((p < blob->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { - int l = asInetAddress(this->routes[this->routeCount].target).unmarshal(blob->data(),(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - if (p >= blob->size()) - return false; - l = asInetAddress(this->routes[this->routeCount].via).unmarshal(blob->data(),(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - if ((p + 4) > blob->size()) - return false; - this->routes[this->routeCount].flags = Utils::loadBigEndian(blob->data() + p); p += 2; - this->routes[this->routeCount].metric = Utils::loadBigEndian(blob->data() + p); p += 2; - ++this->routeCount; - } - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); + if (! blob->empty()) { + unsigned int p = 0; + while ((p < blob->size()) && (routeCount < ZT_MAX_NETWORK_ROUTES)) { + int l = asInetAddress(this->routes[this->routeCount].target) + .unmarshal(blob->data(), (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + if (p >= blob->size()) + return false; + l = asInetAddress(this->routes[this->routeCount].via) + .unmarshal(blob->data(), (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + if ((p + 4) > blob->size()) + return false; + this->routes[this->routeCount].flags = Utils::loadBigEndian(blob->data() + p); + p += 2; + this->routes[this->routeCount].metric = Utils::loadBigEndian(blob->data() + p); + p += 2; + ++this->routeCount; + } + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); - if (!blob->empty()) { - unsigned int p = 0; - while ((p < blob->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - int l = this->staticIps[this->staticIpCount].unmarshal(blob->data() + p,(int)(blob->size() - p)); - if (l < 0) - return false; - p += l; - ++this->staticIpCount; - } - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); + if (! blob->empty()) { + unsigned int p = 0; + while ((p < blob->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + int l = this->staticIps[this->staticIpCount].unmarshal(blob->data() + p, (int)(blob->size() - p)); + if (l < 0) + return false; + p += l; + ++this->staticIpCount; + } + } - blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); - if (!blob->empty()) { - this->ruleCount = 0; - if (CapabilityCredential::unmarshalVirtualNetworkRules(blob->data(), (int)blob->size(), this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES) < 0) - return false; - } - } + blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); + if (! blob->empty()) { + this->ruleCount = 0; + if (CapabilityCredential::unmarshalVirtualNetworkRules( + blob->data(), + (int)blob->size(), + this->rules, + this->ruleCount, + ZT_MAX_NETWORK_RULES) + < 0) + return false; + } + } - return true; - } catch ( ... ) {} - return false; + return true; + } + catch (...) { + } + return false; } -bool NetworkConfig::addSpecialist(const Address &a,const uint64_t f) noexcept +bool NetworkConfig::addSpecialist(const Address& a, const uint64_t f) noexcept { - const uint64_t aint = a.toInt(); - for(unsigned int i=0;i #include +#include namespace ZeroTier { @@ -144,239 +144,255 @@ namespace ZeroTier { /** * Network configuration received from network controller nodes */ -struct NetworkConfig : TriviallyCopyable -{ - ZT_INLINE NetworkConfig() noexcept - { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) +struct NetworkConfig : TriviallyCopyable { + ZT_INLINE NetworkConfig() noexcept + { + memoryZero(this); + } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) - /** - * Write this network config to a dictionary for transport - * - * @param d Dictionary - * @return True if dictionary was successfully created, false if e.g. overflow - */ - bool toDictionary(Dictionary &d) const; + /** + * Write this network config to a dictionary for transport + * + * @param d Dictionary + * @return True if dictionary was successfully created, false if e.g. overflow + */ + bool toDictionary(Dictionary& d) const; - /** - * Read this network config from a dictionary - * - * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) - * @return True if dictionary was valid and network config successfully initialized - */ - bool fromDictionary(const Dictionary &d); + /** + * Read this network config from a dictionary + * + * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) + * @return True if dictionary was valid and network config successfully initialized + */ + bool fromDictionary(const Dictionary& d); - /** - * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network - */ - ZT_INLINE bool enableBroadcast() const noexcept - { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } + /** + * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network + */ + ZT_INLINE bool enableBroadcast() const noexcept + { + return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); + } - /** - * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns - */ - ZT_INLINE bool ndpEmulation() const noexcept - { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } + /** + * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns + */ + ZT_INLINE bool ndpEmulation() const noexcept + { + return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); + } - /** - * @return Network type is public (no access control) - */ - ZT_INLINE bool isPublic() const noexcept - { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } + /** + * @return Network type is public (no access control) + */ + ZT_INLINE bool isPublic() const noexcept + { + return (this->type == ZT_NETWORK_TYPE_PUBLIC); + } - /** - * @return Network type is private (certificate access control) - */ - ZT_INLINE bool isPrivate() const noexcept - { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } + /** + * @return Network type is private (certificate access control) + */ + ZT_INLINE bool isPrivate() const noexcept + { + return (this->type == ZT_NETWORK_TYPE_PRIVATE); + } - /** - * @param fromPeer Peer attempting to bridge other Ethernet peers onto network - * @return True if this network allows bridging - */ - ZT_INLINE bool permitsBridging(const Address &fromPeer) const noexcept - { - for (unsigned int i = 0;i < specialistCount;++i) { - if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK)) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) - return true; - } - return false; - } + /** + * @param fromPeer Peer attempting to bridge other Ethernet peers onto network + * @return True if this network allows bridging + */ + ZT_INLINE bool permitsBridging(const Address& fromPeer) const noexcept + { + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK)) + && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) + return true; + } + return false; + } - ZT_INLINE operator bool() const noexcept - { return (networkId != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) - ZT_INLINE bool operator==(const NetworkConfig &nc) const noexcept - { return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0); } + ZT_INLINE operator bool() const noexcept + { + return (networkId != 0); + } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) + ZT_INLINE bool operator==(const NetworkConfig& nc) const noexcept + { + return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0); + } - ZT_INLINE bool operator!=(const NetworkConfig &nc) const noexcept - { return (!(*this == nc)); } + ZT_INLINE bool operator!=(const NetworkConfig& nc) const noexcept + { + return (! (*this == nc)); + } - /** - * Add a specialist or mask flags if already present - * - * This masks the existing flags if the specialist is already here or adds - * it otherwise. - * - * @param a Address of specialist - * @param f Flags (OR of specialist role/type flags) - * @return True if successfully masked or added - */ - bool addSpecialist(const Address &a, uint64_t f) noexcept; + /** + * Add a specialist or mask flags if already present + * + * This masks the existing flags if the specialist is already here or adds + * it otherwise. + * + * @param a Address of specialist + * @param f Flags (OR of specialist role/type flags) + * @return True if successfully masked or added + */ + bool addSpecialist(const Address& a, uint64_t f) noexcept; - ZT_INLINE const CapabilityCredential *capability(const uint32_t id) const - { - for (unsigned int i = 0;i < capabilityCount;++i) { - if (capabilities[i].id() == id) - return &(capabilities[i]); - } - return nullptr; - } + ZT_INLINE const CapabilityCredential* capability(const uint32_t id) const + { + for (unsigned int i = 0; i < capabilityCount; ++i) { + if (capabilities[i].id() == id) + return &(capabilities[i]); + } + return nullptr; + } - ZT_INLINE const TagCredential *tag(const uint32_t id) const - { - for (unsigned int i = 0;i < tagCount;++i) { - if (tags[i].id() == id) - return &(tags[i]); - } - return nullptr; - } + ZT_INLINE const TagCredential* tag(const uint32_t id) const + { + for (unsigned int i = 0; i < tagCount; ++i) { + if (tags[i].id() == id) + return &(tags[i]); + } + return nullptr; + } - /** - * Network ID that this configuration applies to - */ - uint64_t networkId; + /** + * Network ID that this configuration applies to + */ + uint64_t networkId; - /** - * Controller-side time of config generation/issue - */ - int64_t timestamp; + /** + * Controller-side time of config generation/issue + */ + int64_t timestamp; - /** - * Max difference between timestamp and tag/capability timestamp - */ - int64_t credentialTimeMaxDelta; + /** + * Max difference between timestamp and tag/capability timestamp + */ + int64_t credentialTimeMaxDelta; - /** - * Controller-side revision counter for this configuration - */ - uint64_t revision; + /** + * Controller-side revision counter for this configuration + */ + uint64_t revision; - /** - * Address of device to which this config is issued - */ - Address issuedTo; + /** + * Address of device to which this config is issued + */ + Address issuedTo; - /** - * Hash of identity public key(s) of node to whom this is issued - * - * If this field is all zero it is treated as undefined since old controllers - * do not set it. - */ - uint8_t issuedToFingerprintHash[ZT_FINGERPRINT_HASH_SIZE]; + /** + * Hash of identity public key(s) of node to whom this is issued + * + * If this field is all zero it is treated as undefined since old controllers + * do not set it. + */ + uint8_t issuedToFingerprintHash[ZT_FINGERPRINT_HASH_SIZE]; - /** - * Flags (64-bit) - */ - uint64_t flags; + /** + * Flags (64-bit) + */ + uint64_t flags; - /** - * Network MTU - */ - unsigned int mtu; + /** + * Network MTU + */ + unsigned int mtu; - /** - * Maximum number of recipients per multicast (not including active bridges) - */ - unsigned int multicastLimit; + /** + * Maximum number of recipients per multicast (not including active bridges) + */ + unsigned int multicastLimit; - /** - * Number of specialists - */ - unsigned int specialistCount; + /** + * Number of specialists + */ + unsigned int specialistCount; - /** - * Number of routes - */ - unsigned int routeCount; + /** + * Number of routes + */ + unsigned int routeCount; - /** - * Number of ZT-managed static IP assignments - */ - unsigned int staticIpCount; + /** + * Number of ZT-managed static IP assignments + */ + unsigned int staticIpCount; - /** - * Number of rule table entries - */ - unsigned int ruleCount; + /** + * Number of rule table entries + */ + unsigned int ruleCount; - /** - * Number of capabilities - */ - unsigned int capabilityCount; + /** + * Number of capabilities + */ + unsigned int capabilityCount; - /** - * Number of tags - */ - unsigned int tagCount; + /** + * Number of tags + */ + unsigned int tagCount; - /** - * Number of certificates of ownership - */ - unsigned int certificateOfOwnershipCount; + /** + * Number of certificates of ownership + */ + unsigned int certificateOfOwnershipCount; - /** - * Specialist devices - * - * For each entry the least significant 40 bits are the device's ZeroTier - * address and the most significant 24 bits are flags indicating its role. - */ - uint64_t specialists[ZT_MAX_NETWORK_SPECIALISTS]; + /** + * Specialist devices + * + * For each entry the least significant 40 bits are the device's ZeroTier + * address and the most significant 24 bits are flags indicating its role. + */ + uint64_t specialists[ZT_MAX_NETWORK_SPECIALISTS]; - /** - * Statically defined "pushed" routes (including default gateways) - */ - ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; + /** + * Statically defined "pushed" routes (including default gateways) + */ + ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; - /** - * Static IP assignments - */ - InetAddress staticIps[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + /** + * Static IP assignments + */ + InetAddress staticIps[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; - /** - * Base network rules - */ - ZT_VirtualNetworkRule rules[ZT_MAX_NETWORK_RULES]; + /** + * Base network rules + */ + ZT_VirtualNetworkRule rules[ZT_MAX_NETWORK_RULES]; - /** - * Capabilities for this node on this network, in ascending order of capability ID - */ - CapabilityCredential capabilities[ZT_MAX_NETWORK_CAPABILITIES]; + /** + * Capabilities for this node on this network, in ascending order of capability ID + */ + CapabilityCredential capabilities[ZT_MAX_NETWORK_CAPABILITIES]; - /** - * Tags for this node on this network, in ascending order of tag ID - */ - TagCredential tags[ZT_MAX_NETWORK_TAGS]; + /** + * Tags for this node on this network, in ascending order of tag ID + */ + TagCredential tags[ZT_MAX_NETWORK_TAGS]; - /** - * Certificates of ownership for this network member - */ - OwnershipCredential certificatesOfOwnership[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; + /** + * Certificates of ownership for this network member + */ + OwnershipCredential certificatesOfOwnership[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; - /** - * Network type (currently just public or private) - */ - ZT_VirtualNetworkType type; + /** + * Network type (currently just public or private) + */ + ZT_VirtualNetworkType type; - /** - * Network short name or empty string if not defined - */ - char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; + /** + * Network short name or empty string if not defined + */ + char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; - /** - * Certificate of membership (for private networks) - */ - MembershipCredential com; + /** + * Certificate of membership (for private networks) + */ + MembershipCredential com; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/NetworkController.hpp b/core/NetworkController.hpp index 202fdd10d..4dbe9533a 100644 --- a/core/NetworkController.hpp +++ b/core/NetworkController.hpp @@ -14,11 +14,11 @@ #ifndef ZT_NETWORKCONFIGMASTER_HPP #define ZT_NETWORKCONFIGMASTER_HPP +#include "Address.hpp" #include "Constants.hpp" #include "Dictionary.hpp" #include "NetworkConfig.hpp" #include "RevocationCredential.hpp" -#include "Address.hpp" namespace ZeroTier { @@ -28,82 +28,104 @@ struct InetAddress; /** * Interface for network controller implementations */ -class NetworkController -{ -public: - enum ErrorCode - { - NC_ERROR_NONE = 0, - NC_ERROR_OBJECT_NOT_FOUND = 1, - NC_ERROR_ACCESS_DENIED = 2, - NC_ERROR_INTERNAL_SERVER_ERROR = 3 - }; +class NetworkController { + public: + enum ErrorCode { + NC_ERROR_NONE = 0, + NC_ERROR_OBJECT_NOT_FOUND = 1, + NC_ERROR_ACCESS_DENIED = 2, + NC_ERROR_INTERNAL_SERVER_ERROR = 3 + }; - /** - * Interface for sender used to send pushes and replies - */ - class Sender - { - public: - /** - * Send a configuration to a remote peer - * - * @param nwid Network ID - * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) - * @param destination Destination peer Address - * @param nc Network configuration to send - * @param sendLegacyFormatConfig If true, send an old-format network config - */ - virtual void ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig) = 0; + /** + * Interface for sender used to send pushes and replies + */ + class Sender { + public: + /** + * Send a configuration to a remote peer + * + * @param nwid Network ID + * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG + * (push) + * @param destination Destination peer Address + * @param nc Network configuration to send + * @param sendLegacyFormatConfig If true, send an old-format network config + */ + virtual void ncSendConfig( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + const NetworkConfig& nc, + bool sendLegacyFormatConfig) = 0; - /** - * Send revocation to a node - * - * @param destination Destination node address - * @param rev Revocation to send - */ - virtual void ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev) = 0; + /** + * Send revocation to a node + * + * @param destination Destination node address + * @param rev Revocation to send + */ + virtual void ncSendRevocation( + void* tPtr, + int64_t clock, + int64_t ticks, + const Address& destination, + const RevocationCredential& rev) = 0; - /** - * Send a network configuration request error - * - * @param nwid Network ID - * @param requestPacketId Request packet ID or 0 if none - * @param destination Destination peer Address - * @param errorCode Error code - */ - virtual void ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode) = 0; - }; + /** + * Send a network configuration request error + * + * @param nwid Network ID + * @param requestPacketId Request packet ID or 0 if none + * @param destination Destination peer Address + * @param errorCode Error code + */ + virtual void ncSendError( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + NetworkController::ErrorCode errorCode) = 0; + }; - NetworkController() {} - virtual ~NetworkController() {} + NetworkController() + { + } + virtual ~NetworkController() + { + } - /** - * Called when this is added to a Node to initialize and supply info - * - * @param signingId Identity for signing of network configurations, certs, etc. - * @param sender Sender implementation for sending replies or config pushes - */ - virtual void init(const Identity &signingId, Sender *sender) = 0; + /** + * Called when this is added to a Node to initialize and supply info + * + * @param signingId Identity for signing of network configurations, certs, etc. + * @param sender Sender implementation for sending replies or config pushes + */ + virtual void init(const Identity& signingId, Sender* sender) = 0; - /** - * Handle a network configuration request - * - * @param nwid 64-bit network ID - * @param fromAddr Originating wire address or null address if packet is not direct (or from self) - * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request - * @param identity ZeroTier identity of originating peer - * @param metaData Meta-data bundled with request (if any) - * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error - */ - virtual void request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData) = 0; + /** + * Handle a network configuration request + * + * @param nwid 64-bit network ID + * @param fromAddr Originating wire address or null address if packet is not direct (or from self) + * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request + * @param identity ZeroTier identity of originating peer + * @param metaData Meta-data bundled with request (if any) + * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error + */ + virtual void request( + uint64_t nwid, + const InetAddress& fromAddr, + uint64_t requestPacketId, + const Identity& identity, + const Dictionary& metaData) = 0; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Node.cpp b/core/Node.cpp index f82861646..762618cb4 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -11,745 +11,814 @@ */ /****/ -#include "Constants.hpp" -#include "SharedPtr.hpp" #include "Node.hpp" -#include "NetworkController.hpp" -#include "Topology.hpp" + #include "Address.hpp" -#include "Identity.hpp" -#include "SelfAwareness.hpp" -#include "Network.hpp" -#include "Trace.hpp" -#include "Locator.hpp" +#include "Buf.hpp" +#include "Constants.hpp" #include "Expect.hpp" +#include "Identity.hpp" +#include "Locator.hpp" +#include "Network.hpp" +#include "NetworkController.hpp" +#include "SelfAwareness.hpp" +#include "SharedPtr.hpp" +#include "Store.hpp" +#include "Topology.hpp" +#include "Trace.hpp" +#include "TrustStore.hpp" #include "VL1.hpp" #include "VL2.hpp" -#include "Buf.hpp" -#include "TrustStore.hpp" -#include "Store.hpp" namespace ZeroTier { namespace { -struct _NodeObjects -{ - ZT_INLINE _NodeObjects(Context &ctx, const CallContext &cc) : - networks(), - t(ctx), - expect(), - vl2(ctx), - vl1(ctx), - topology(ctx, cc), - sa(ctx), - ts() - { - ctx.networks = &networks; - ctx.t = &t; - ctx.expect = &expect; - ctx.vl2 = &vl2; - ctx.vl1 = &vl1; - ctx.topology = &topology; - ctx.sa = &sa; - ctx.ts = &ts; - } +struct _NodeObjects { + ZT_INLINE _NodeObjects(Context& ctx, const CallContext& cc) + : networks() + , t(ctx) + , expect() + , vl2(ctx) + , vl1(ctx) + , topology(ctx, cc) + , sa(ctx) + , ts() + { + ctx.networks = &networks; + ctx.t = &t; + ctx.expect = &expect; + ctx.vl2 = &vl2; + ctx.vl1 = &vl1; + ctx.topology = &topology; + ctx.sa = &sa; + ctx.ts = &ts; + } - TinyMap< SharedPtr< Network > > networks; - Trace t; - Expect expect; - VL2 vl2; - VL1 vl1; - Topology topology; - SelfAwareness sa; - TrustStore ts; + TinyMap > networks; + Trace t; + Expect expect; + VL2 vl2; + VL1 vl1; + Topology topology; + SelfAwareness sa; + TrustStore ts; }; -} // anonymous namespace +} // anonymous namespace -Node::Node(void *uPtr, const struct ZT_Node_Callbacks *callbacks, const CallContext &cc) : - m_ctx(this), - m_store(m_ctx), - m_objects(nullptr), - m_lastPeerPulse(0), - m_lastHousekeepingRun(0), - m_lastNetworkHousekeepingRun(0), - m_lastTrustStoreUpdate(0), - m_online(false) +Node::Node(void* uPtr, const struct ZT_Node_Callbacks* callbacks, const CallContext& cc) + : m_ctx(this) + , m_store(m_ctx) + , m_objects(nullptr) + , m_lastPeerPulse(0) + , m_lastHousekeepingRun(0) + , m_lastNetworkHousekeepingRun(0) + , m_lastTrustStoreUpdate(0) + , m_online(false) { - ZT_SPEW("Node starting up!"); + ZT_SPEW("Node starting up!"); - Utils::copy< sizeof(ZT_Node_Callbacks) >(&m_ctx.cb, callbacks); - m_ctx.uPtr = uPtr; - m_ctx.store = &m_store; + Utils::copy(&m_ctx.cb, callbacks); + m_ctx.uPtr = uPtr; + m_ctx.store = &m_store; - Vector< uint8_t > data(m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0)); - bool haveIdentity = false; - if (!data.empty()) { - data.push_back(0); // zero-terminate string - if (m_ctx.identity.fromString((const char *)data.data())) { - m_ctx.identity.toString(false, m_ctx.publicIdentityStr); - m_ctx.identity.toString(true, m_ctx.secretIdentityStr); - haveIdentity = true; - ZT_SPEW("loaded identity %s", m_ctx.identity.toString().c_str()); - } - } + Vector data(m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0)); + bool haveIdentity = false; + if (! data.empty()) { + data.push_back(0); // zero-terminate string + if (m_ctx.identity.fromString((const char*)data.data())) { + m_ctx.identity.toString(false, m_ctx.publicIdentityStr); + m_ctx.identity.toString(true, m_ctx.secretIdentityStr); + haveIdentity = true; + ZT_SPEW("loaded identity %s", m_ctx.identity.toString().c_str()); + } + } - if (!haveIdentity) { - m_ctx.identity.generate(Identity::C25519); - m_ctx.identity.toString(false, m_ctx.publicIdentityStr); - m_ctx.identity.toString(true, m_ctx.secretIdentityStr); - m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0, m_ctx.secretIdentityStr, (unsigned int)strlen(m_ctx.secretIdentityStr)); - m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0, m_ctx.publicIdentityStr, (unsigned int)strlen(m_ctx.publicIdentityStr)); - ZT_SPEW("no pre-existing identity found, created %s", m_ctx.identity.toString().c_str()); - } else { - data = m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0); - if ((data.empty()) || (memcmp(data.data(), m_ctx.publicIdentityStr, strlen(m_ctx.publicIdentityStr)) != 0)) - m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0, m_ctx.publicIdentityStr, (unsigned int)strlen(m_ctx.publicIdentityStr)); - } + if (! haveIdentity) { + m_ctx.identity.generate(Identity::C25519); + m_ctx.identity.toString(false, m_ctx.publicIdentityStr); + m_ctx.identity.toString(true, m_ctx.secretIdentityStr); + m_store.put( + cc, + ZT_STATE_OBJECT_IDENTITY_SECRET, + Utils::ZERO256, + 0, + m_ctx.secretIdentityStr, + (unsigned int)strlen(m_ctx.secretIdentityStr)); + m_store.put( + cc, + ZT_STATE_OBJECT_IDENTITY_PUBLIC, + Utils::ZERO256, + 0, + m_ctx.publicIdentityStr, + (unsigned int)strlen(m_ctx.publicIdentityStr)); + ZT_SPEW("no pre-existing identity found, created %s", m_ctx.identity.toString().c_str()); + } + else { + data = m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0); + if ((data.empty()) || (memcmp(data.data(), m_ctx.publicIdentityStr, strlen(m_ctx.publicIdentityStr)) != 0)) + m_store.put( + cc, + ZT_STATE_OBJECT_IDENTITY_PUBLIC, + Utils::ZERO256, + 0, + m_ctx.publicIdentityStr, + (unsigned int)strlen(m_ctx.publicIdentityStr)); + } - uint8_t localSecretCipherKey[ZT_FINGERPRINT_HASH_SIZE]; - m_ctx.identity.hashWithPrivate(localSecretCipherKey); - ++localSecretCipherKey[0]; - SHA384(localSecretCipherKey, localSecretCipherKey, ZT_FINGERPRINT_HASH_SIZE); - m_ctx.localSecretCipher.init(localSecretCipherKey); + uint8_t localSecretCipherKey[ZT_FINGERPRINT_HASH_SIZE]; + m_ctx.identity.hashWithPrivate(localSecretCipherKey); + ++localSecretCipherKey[0]; + SHA384(localSecretCipherKey, localSecretCipherKey, ZT_FINGERPRINT_HASH_SIZE); + m_ctx.localSecretCipher.init(localSecretCipherKey); - for (unsigned int i = 0; i < 1023; ++i) - m_ctx.randomPrivilegedPortOrder[i] = (uint16_t)(i + 1); - for (unsigned int i = 0; i < 512; ++i) { - uint64_t rn = Utils::random(); - const unsigned int a = (unsigned int)rn % 1023; - const unsigned int b = (unsigned int)(rn >> 32U) % 1023; - if (a != b) { - const uint16_t tmp = m_ctx.randomPrivilegedPortOrder[a]; - m_ctx.randomPrivilegedPortOrder[a] = m_ctx.randomPrivilegedPortOrder[b]; - m_ctx.randomPrivilegedPortOrder[b] = tmp; - } - } + for (unsigned int i = 0; i < 1023; ++i) + m_ctx.randomPrivilegedPortOrder[i] = (uint16_t)(i + 1); + for (unsigned int i = 0; i < 512; ++i) { + uint64_t rn = Utils::random(); + const unsigned int a = (unsigned int)rn % 1023; + const unsigned int b = (unsigned int)(rn >> 32U) % 1023; + if (a != b) { + const uint16_t tmp = m_ctx.randomPrivilegedPortOrder[a]; + m_ctx.randomPrivilegedPortOrder[a] = m_ctx.randomPrivilegedPortOrder[b]; + m_ctx.randomPrivilegedPortOrder[b] = tmp; + } + } - m_objects = new _NodeObjects(m_ctx, cc); + m_objects = new _NodeObjects(m_ctx, cc); - ZT_SPEW("node initialized!"); - postEvent(cc.tPtr, ZT_EVENT_UP); + ZT_SPEW("node initialized!"); + postEvent(cc.tPtr, ZT_EVENT_UP); } Node::~Node() { - ZT_SPEW("Node shutting down (in destructor)."); + ZT_SPEW("Node shutting down (in destructor)."); - m_allNetworks_l.lock(); - m_ctx.networks->clear(); - m_allNetworks.clear(); - m_allNetworks_l.unlock(); + m_allNetworks_l.lock(); + m_ctx.networks->clear(); + m_allNetworks.clear(); + m_allNetworks_l.unlock(); - delete reinterpret_cast<_NodeObjects *>(m_objects); + delete reinterpret_cast<_NodeObjects*>(m_objects); - // Let go of cached Buf objects. If other nodes happen to be running in this - // same process space new Bufs will be allocated as needed, but this is almost - // never the case. Calling this here saves RAM if we are running inside something - // that wants to keep running after tearing down its ZeroTier core instance. - Buf::freePool(); + // Let go of cached Buf objects. If other nodes happen to be running in this + // same process space new Bufs will be allocated as needed, but this is almost + // never the case. Calling this here saves RAM if we are running inside something + // that wants to keep running after tearing down its ZeroTier core instance. + Buf::freePool(); } -void Node::shutdown(const CallContext &cc) +void Node::shutdown(const CallContext& cc) { - m_allNetworks_l.lock(); - m_ctx.networks->clear(); - m_allNetworks.clear(); - m_allNetworks_l.unlock(); + m_allNetworks_l.lock(); + m_ctx.networks->clear(); + m_allNetworks.clear(); + m_allNetworks_l.unlock(); - postEvent(cc.tPtr, ZT_EVENT_DOWN); + postEvent(cc.tPtr, ZT_EVENT_DOWN); - if (m_ctx.topology) - m_ctx.topology->saveAll(cc); + if (m_ctx.topology) + m_ctx.topology->saveAll(cc); } -ZT_ResultCode Node::processBackgroundTasks(const CallContext &cc, volatile int64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(const CallContext& cc, volatile int64_t* nextBackgroundTaskDeadline) { - Mutex::Lock bl(m_backgroundTasksLock); + Mutex::Lock bl(m_backgroundTasksLock); - try { - // Updating the trust store means checking certificates and certificate chains - // against the current time, etc., and also resynchronizing roots as specified by - // certificates. This also happens on demand when the trust store is changed. - if ((cc.ticks - m_lastTrustStoreUpdate) >= ZT_TRUSTSTORE_UPDATE_PERIOD) { - m_lastTrustStoreUpdate = cc.ticks; - if (unlikely(m_ctx.ts->update(cc.ticks, nullptr))) - m_ctx.topology->trustStoreChanged(cc); - } + try { + // Updating the trust store means checking certificates and certificate chains + // against the current time, etc., and also resynchronizing roots as specified by + // certificates. This also happens on demand when the trust store is changed. + if ((cc.ticks - m_lastTrustStoreUpdate) >= ZT_TRUSTSTORE_UPDATE_PERIOD) { + m_lastTrustStoreUpdate = cc.ticks; + if (unlikely(m_ctx.ts->update(cc.ticks, nullptr))) + m_ctx.topology->trustStoreChanged(cc); + } - // Networks perform housekeeping here such as refreshing configs. - if ((cc.ticks - m_lastNetworkHousekeepingRun) >= ZT_NETWORK_HOUSEKEEPING_PERIOD) { - m_lastNetworkHousekeepingRun = cc.ticks; - ZT_SPEW("running networking housekeeping..."); - Mutex::Lock l(m_allNetworks_l); - for (Vector< SharedPtr< Network > >::const_iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) - (*n)->doPeriodicTasks(cc); - } + // Networks perform housekeeping here such as refreshing configs. + if ((cc.ticks - m_lastNetworkHousekeepingRun) >= ZT_NETWORK_HOUSEKEEPING_PERIOD) { + m_lastNetworkHousekeepingRun = cc.ticks; + ZT_SPEW("running networking housekeeping..."); + Mutex::Lock l(m_allNetworks_l); + for (Vector >::const_iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) + (*n)->doPeriodicTasks(cc); + } - // Perform general housekeeping for other objects in the system. - if ((cc.ticks - m_lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { - m_lastHousekeepingRun = cc.ticks; - ZT_SPEW("running housekeeping..."); - m_ctx.topology->doPeriodicTasks(cc); - m_ctx.sa->clean(cc); - } + // Perform general housekeeping for other objects in the system. + if ((cc.ticks - m_lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { + m_lastHousekeepingRun = cc.ticks; + ZT_SPEW("running housekeeping..."); + m_ctx.topology->doPeriodicTasks(cc); + m_ctx.sa->clean(cc); + } - // Peers have a "pulse" method that does things like keepalive and path housekeeping. - // This happens last because keepalives are only necessary if nothing has been sent - // in a while, and some of the above actions may cause peers to send things which may - // reduce the need for keepalives. Root ranking also happens here. - if ((cc.ticks - m_lastPeerPulse) >= ZT_PEER_PULSE_INTERVAL) { - m_lastPeerPulse = cc.ticks; - ZT_SPEW("running pulse() on each peer..."); - try { - Vector< SharedPtr< Peer > > allPeers, rootPeers; - m_ctx.topology->allPeers(allPeers, rootPeers); - std::sort(rootPeers.begin(), rootPeers.end()); + // Peers have a "pulse" method that does things like keepalive and path housekeeping. + // This happens last because keepalives are only necessary if nothing has been sent + // in a while, and some of the above actions may cause peers to send things which may + // reduce the need for keepalives. Root ranking also happens here. + if ((cc.ticks - m_lastPeerPulse) >= ZT_PEER_PULSE_INTERVAL) { + m_lastPeerPulse = cc.ticks; + ZT_SPEW("running pulse() on each peer..."); + try { + Vector > allPeers, rootPeers; + m_ctx.topology->allPeers(allPeers, rootPeers); + std::sort(rootPeers.begin(), rootPeers.end()); - bool online = false; - for (Vector< SharedPtr< Peer > >::iterator p(allPeers.begin()); p != allPeers.end(); ++p) { - (*p)->pulse(m_ctx, cc); - if (!online) { - online = ((std::binary_search(rootPeers.begin(), rootPeers.end(), *p) || rootPeers.empty()) && (*p)->directlyConnected()); - } - } + bool online = false; + for (Vector >::iterator p(allPeers.begin()); p != allPeers.end(); ++p) { + (*p)->pulse(m_ctx, cc); + if (! online) { + online = + ((std::binary_search(rootPeers.begin(), rootPeers.end(), *p) || rootPeers.empty()) + && (*p)->directlyConnected()); + } + } - if (unlikely(m_online.exchange(online, std::memory_order_relaxed) != online)) - postEvent(cc.tPtr, online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); + if (unlikely(m_online.exchange(online, std::memory_order_relaxed) != online)) + postEvent(cc.tPtr, online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); - ZT_SPEW("ranking roots..."); - m_ctx.topology->rankRoots(cc); - } catch (...) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - } + ZT_SPEW("ranking roots..."); + m_ctx.topology->rankRoots(cc); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } + } - *nextBackgroundTaskDeadline = cc.ticks + ZT_TIMER_TASK_INTERVAL; - } catch (...) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + *nextBackgroundTaskDeadline = cc.ticks + ZT_TIMER_TASK_INTERVAL; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } - return ZT_RESULT_OK; + return ZT_RESULT_OK; } -ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, const CallContext &cc) +ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint* controllerFingerprint, void* uptr, const CallContext& cc) { - Mutex::Lock l(m_allNetworks_l); + Mutex::Lock l(m_allNetworks_l); - Fingerprint fp; - if (controllerFingerprint) { - fp = *controllerFingerprint; - ZT_SPEW("joining network %.16llx with controller fingerprint %s", nwid, fp.toString().c_str()); - } else { - ZT_SPEW("joining network %.16llx", nwid); - } + Fingerprint fp; + if (controllerFingerprint) { + fp = *controllerFingerprint; + ZT_SPEW("joining network %.16llx with controller fingerprint %s", nwid, fp.toString().c_str()); + } + else { + ZT_SPEW("joining network %.16llx", nwid); + } - for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { - if ((*n)->id() == nwid) - return ZT_RESULT_OK; - } - SharedPtr< Network > network(new Network(m_ctx, cc, nwid, fp, uptr, nullptr)); - m_allNetworks.push_back(network); - m_ctx.networks->set(nwid, network); + for (Vector >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { + if ((*n)->id() == nwid) + return ZT_RESULT_OK; + } + SharedPtr network(new Network(m_ctx, cc, nwid, fp, uptr, nullptr)); + m_allNetworks.push_back(network); + m_ctx.networks->set(nwid, network); - return ZT_RESULT_OK; + return ZT_RESULT_OK; } -ZT_ResultCode Node::leave(uint64_t nwid, void **uptr, const CallContext &cc) +ZT_ResultCode Node::leave(uint64_t nwid, void** uptr, const CallContext& cc) { - Mutex::Lock l(m_allNetworks_l); + Mutex::Lock l(m_allNetworks_l); - ZT_SPEW("leaving network %.16llx", nwid); - ZT_VirtualNetworkConfig ctmp; + ZT_SPEW("leaving network %.16llx", nwid); + ZT_VirtualNetworkConfig ctmp; - SharedPtr< Network > network; - m_ctx.networks->erase(nwid); - for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { - if ((*n)->id() == nwid) { - network.move(*n); - m_allNetworks.erase(n); - break; - } - } + SharedPtr network; + m_ctx.networks->erase(nwid); + for (Vector >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { + if ((*n)->id() == nwid) { + network.move(*n); + m_allNetworks.erase(n); + break; + } + } - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; - m_store.erase(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1); + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; + m_store.erase(cc, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1); - if (network) { - if (uptr) - *uptr = *network->userPtr(); - network->externalConfig(&ctmp); - m_ctx.cb.virtualNetworkConfigFunction(reinterpret_cast(this), m_ctx.uPtr, cc.tPtr, nwid, network->userPtr(), ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY, &ctmp); - network->destroy(); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + if (network) { + if (uptr) + *uptr = *network->userPtr(); + network->externalConfig(&ctmp); + m_ctx.cb.virtualNetworkConfigFunction( + reinterpret_cast(this), + m_ctx.uPtr, + cc.tPtr, + nwid, + network->userPtr(), + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY, + &ctmp); + network->destroy(); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } -ZT_ResultCode Node::multicastSubscribe(const CallContext &cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) +ZT_ResultCode +Node::multicastSubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - ZT_SPEW("multicast subscribe to %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); - const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); - if (nw) { - nw->multicastSubscribe(cc, MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + ZT_SPEW("multicast subscribe to %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); + const SharedPtr nw(m_ctx.networks->get(nwid)); + if (nw) { + nw->multicastSubscribe(cc, MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } -ZT_ResultCode Node::multicastUnsubscribe(const CallContext &cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) +ZT_ResultCode +Node::multicastUnsubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - ZT_SPEW("multicast unsubscribe from %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); - const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); - if (nw) { - nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + ZT_SPEW("multicast unsubscribe from %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); + const SharedPtr nw(m_ctx.networks->get(nwid)); + if (nw) { + nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } -void Node::status(ZT_NodeStatus *status) const +void Node::status(ZT_NodeStatus* status) const { - status->address = m_ctx.identity.address().toInt(); - status->identity = reinterpret_cast(&m_ctx.identity); - status->publicIdentity = m_ctx.publicIdentityStr; - status->secretIdentity = m_ctx.secretIdentityStr; - status->online = m_online ? 1 : 0; + status->address = m_ctx.identity.address().toInt(); + status->identity = reinterpret_cast(&m_ctx.identity); + status->publicIdentity = m_ctx.publicIdentityStr; + status->secretIdentity = m_ctx.secretIdentityStr; + status->online = m_online ? 1 : 0; } -struct p_ZT_PeerListPrivate : public ZT_PeerList -{ - // Actual containers for the memory, hidden from external users. - Vector< ZT_Peer > p_peers; - ForwardList< Vector< ZT_Path > > p_paths; - ForwardList< Identity > p_identities; - ForwardList< Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX > > p_locators; +struct p_ZT_PeerListPrivate : public ZT_PeerList { + // Actual containers for the memory, hidden from external users. + Vector p_peers; + ForwardList > p_paths; + ForwardList p_identities; + ForwardList > p_locators; }; -static void p_peerListFreeFunction(const void *pl) +static void p_peerListFreeFunction(const void* pl) { - if (pl) - delete reinterpret_cast(const_cast(pl)); + if (pl) + delete reinterpret_cast(const_cast(pl)); } -struct p_sortPeerPtrsByAddress -{ - ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept - { return (a->address() < b->address()); } +struct p_sortPeerPtrsByAddress { + ZT_INLINE bool operator()(const SharedPtr& a, const SharedPtr& b) const noexcept + { + return (a->address() < b->address()); + } }; -ZT_PeerList *Node::peers(const CallContext &cc) const +ZT_PeerList* Node::peers(const CallContext& cc) const { - p_ZT_PeerListPrivate *pl = nullptr; - try { - pl = new p_ZT_PeerListPrivate; - pl->freeFunction = p_peerListFreeFunction; + p_ZT_PeerListPrivate* pl = nullptr; + try { + pl = new p_ZT_PeerListPrivate; + pl->freeFunction = p_peerListFreeFunction; - Vector< SharedPtr< Peer > > peers, rootPeers; - m_ctx.topology->allPeers(peers, rootPeers); - std::sort(peers.begin(), peers.end(), p_sortPeerPtrsByAddress()); - std::sort(rootPeers.begin(), rootPeers.end()); + Vector > peers, rootPeers; + m_ctx.topology->allPeers(peers, rootPeers); + std::sort(peers.begin(), peers.end(), p_sortPeerPtrsByAddress()); + std::sort(rootPeers.begin(), rootPeers.end()); - for (Vector< SharedPtr< Peer > >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { - pl->p_peers.push_back(ZT_Peer()); - ZT_Peer &p = pl->p_peers.back(); - Peer &pp = **pi; + for (Vector >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { + pl->p_peers.push_back(ZT_Peer()); + ZT_Peer& p = pl->p_peers.back(); + Peer& pp = **pi; - p.address = pp.address(); - pl->p_identities.push_front(pp.identity()); - p.identity = reinterpret_cast(&(pl->p_identities.front())); - p.fingerprint = &(pl->p_identities.front().fingerprint()); - uint16_t vProto, vMajor, vMinor, vRevision; - if (pp.remoteVersion(vProto, vMajor, vMinor, vRevision)) { - p.versionMajor = (int)vMajor; - p.versionMinor = (int)vMinor; - p.versionRev = (int)vRevision; - p.versionProto = (int)vProto; - } else { - p.versionMajor = -1; - p.versionMinor = -1; - p.versionRev = -1; - p.versionProto = -1; - } - p.latency = pp.latency(); - p.root = std::binary_search(rootPeers.begin(), rootPeers.end(), *pi) ? 1 : 0; + p.address = pp.address(); + pl->p_identities.push_front(pp.identity()); + p.identity = reinterpret_cast(&(pl->p_identities.front())); + p.fingerprint = &(pl->p_identities.front().fingerprint()); + uint16_t vProto, vMajor, vMinor, vRevision; + if (pp.remoteVersion(vProto, vMajor, vMinor, vRevision)) { + p.versionMajor = (int)vMajor; + p.versionMinor = (int)vMinor; + p.versionRev = (int)vRevision; + p.versionProto = (int)vProto; + } + else { + p.versionMajor = -1; + p.versionMinor = -1; + p.versionRev = -1; + p.versionProto = -1; + } + p.latency = pp.latency(); + p.root = std::binary_search(rootPeers.begin(), rootPeers.end(), *pi) ? 1 : 0; - p.networks = nullptr; - p.networkCount = 0; // TODO: networks this peer belongs to + p.networks = nullptr; + p.networkCount = 0; // TODO: networks this peer belongs to - Vector< SharedPtr< Path > > ztPaths; - pp.getAllPaths(ztPaths); - if (ztPaths.empty()) { - pl->p_paths.push_front(Vector< ZT_Path >()); - std::vector< ZT_Path > &apiPaths = pl->p_paths.front(); - apiPaths.resize(ztPaths.size()); - for (unsigned long i = 0; i < (unsigned long)ztPaths.size(); ++i) { - SharedPtr< Path > &ztp = ztPaths[i]; - ZT_Path &apip = apiPaths[i]; - apip.endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; - Utils::copy< sizeof(struct sockaddr_storage) >(&(apip.endpoint.value.ss), &(ztp->address().as.ss)); - apip.lastSend = ztp->lastOut(); - apip.lastReceive = ztp->lastIn(); - apip.alive = ztp->alive(cc) ? 1 : 0; - apip.preferred = (i == 0) ? 1 : 0; - } - p.paths = apiPaths.data(); - p.pathCount = (unsigned int)apiPaths.size(); - } else { - p.paths = nullptr; - p.pathCount = 0; - } + Vector > ztPaths; + pp.getAllPaths(ztPaths); + if (ztPaths.empty()) { + pl->p_paths.push_front(Vector()); + std::vector& apiPaths = pl->p_paths.front(); + apiPaths.resize(ztPaths.size()); + for (unsigned long i = 0; i < (unsigned long)ztPaths.size(); ++i) { + SharedPtr& ztp = ztPaths[i]; + ZT_Path& apip = apiPaths[i]; + apip.endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; + Utils::copy(&(apip.endpoint.value.ss), &(ztp->address().as.ss)); + apip.lastSend = ztp->lastOut(); + apip.lastReceive = ztp->lastIn(); + apip.alive = ztp->alive(cc) ? 1 : 0; + apip.preferred = (i == 0) ? 1 : 0; + } + p.paths = apiPaths.data(); + p.pathCount = (unsigned int)apiPaths.size(); + } + else { + p.paths = nullptr; + p.pathCount = 0; + } - const SharedPtr< const Locator > loc(pp.locator()); - if (loc) { - pl->p_locators.push_front(Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX >()); - Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX > &lb = pl->p_locators.front(); - Utils::zero< ZT_LOCATOR_MARSHAL_SIZE_MAX >(lb.data); - const int ls = loc->marshal(lb.data); - if (ls > 0) { - p.locatorSize = (unsigned int)ls; - p.locator = lb.data; - } - } - } + const SharedPtr loc(pp.locator()); + if (loc) { + pl->p_locators.push_front(Blob()); + Blob& lb = pl->p_locators.front(); + Utils::zero(lb.data); + const int ls = loc->marshal(lb.data); + if (ls > 0) { + p.locatorSize = (unsigned int)ls; + p.locator = lb.data; + } + } + } - pl->peers = pl->p_peers.data(); - pl->peerCount = (unsigned long)pl->p_peers.size(); + pl->peers = pl->p_peers.data(); + pl->peerCount = (unsigned long)pl->p_peers.size(); - return pl; - } catch (...) { - delete pl; - return nullptr; - } + return pl; + } + catch (...) { + delete pl; + return nullptr; + } } -ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const +ZT_VirtualNetworkConfig* Node::networkConfig(uint64_t nwid) const { - const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); - if (nw) { - ZT_VirtualNetworkConfig *const nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig)); - nw->externalConfig(nc); - return nc; - } else { - return nullptr; - } + const SharedPtr nw(m_ctx.networks->get(nwid)); + if (nw) { + ZT_VirtualNetworkConfig* const nc = (ZT_VirtualNetworkConfig*)::malloc(sizeof(ZT_VirtualNetworkConfig)); + nw->externalConfig(nc); + return nc; + } + else { + return nullptr; + } } -ZT_VirtualNetworkList *Node::networks() const +ZT_VirtualNetworkList* Node::networks() const { - Mutex::Lock l(m_allNetworks_l); + Mutex::Lock l(m_allNetworks_l); - char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_allNetworks.size())); - if (!buf) - return nullptr; - ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; - nl->freeFunction = reinterpret_cast(free); - nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); + char* const buf = + (char*)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_allNetworks.size())); + if (! buf) + return nullptr; + ZT_VirtualNetworkList* nl = (ZT_VirtualNetworkList*)buf; + nl->freeFunction = reinterpret_cast(free); + nl->networks = (ZT_VirtualNetworkConfig*)(buf + sizeof(ZT_VirtualNetworkList)); - nl->networkCount = 0; - for (Vector< SharedPtr< Network > >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) - (*i)->externalConfig(&(nl->networks[nl->networkCount++])); + nl->networkCount = 0; + for (Vector >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) + (*i)->externalConfig(&(nl->networks[nl->networkCount++])); - return nl; + return nl; } -void Node::setNetworkUserPtr( - uint64_t nwid, - void *ptr) +void Node::setNetworkUserPtr(uint64_t nwid, void* ptr) { - SharedPtr< Network > nw(m_ctx.networks->get(nwid)); - if (nw) { - m_allNetworks_l.lock(); // ensure no concurrent modification of user PTR in network - *(nw->userPtr()) = ptr; - m_allNetworks_l.unlock(); - } + SharedPtr nw(m_ctx.networks->get(nwid)); + if (nw) { + m_allNetworks_l.lock(); // ensure no concurrent modification of user PTR in network + *(nw->userPtr()) = ptr; + m_allNetworks_l.unlock(); + } } -void Node::setInterfaceAddresses( - const ZT_InterfaceAddress *addrs, - unsigned int addrCount) +void Node::setInterfaceAddresses(const ZT_InterfaceAddress* addrs, unsigned int addrCount) { - Mutex::Lock _l(m_localInterfaceAddresses_m); - m_localInterfaceAddresses.clear(); - for (unsigned int i = 0; i < addrCount; ++i) { - bool dupe = false; - for (unsigned int j = 0; j < i; ++j) { - if (*(reinterpret_cast(&addrs[j].address)) == *(reinterpret_cast(&addrs[i].address))) { - dupe = true; - break; - } - } - if (!dupe) - m_localInterfaceAddresses.push_back(addrs[i]); - } + Mutex::Lock _l(m_localInterfaceAddresses_m); + m_localInterfaceAddresses.clear(); + for (unsigned int i = 0; i < addrCount; ++i) { + bool dupe = false; + for (unsigned int j = 0; j < i; ++j) { + if (*(reinterpret_cast(&addrs[j].address)) + == *(reinterpret_cast(&addrs[i].address))) { + dupe = true; + break; + } + } + if (! dupe) + m_localInterfaceAddresses.push_back(addrs[i]); + } } ZT_CertificateError Node::addCertificate( - const CallContext &cc, - unsigned int localTrust, - const ZT_Certificate *cert, - const void *certData, - unsigned int certSize) + const CallContext& cc, + unsigned int localTrust, + const ZT_Certificate* cert, + const void* certData, + unsigned int certSize) { - Certificate c; - if (cert) { - c = *cert; - } else { - if ((!certData) || (!certSize)) - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - if (!c.decode(certData, certSize)) - return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - } - m_ctx.ts->add(c, localTrust); - m_ctx.ts->update(cc.clock, nullptr); - SharedPtr< TrustStore::Entry > ent(m_ctx.ts->get(c.getSerialNo())); - return (ent) ? ent->error() : ZT_CERTIFICATE_ERROR_INVALID_FORMAT; // should never be null, but if so it means invalid + Certificate c; + if (cert) { + c = *cert; + } + else { + if ((! certData) || (! certSize)) + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + if (! c.decode(certData, certSize)) + return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; + } + m_ctx.ts->add(c, localTrust); + m_ctx.ts->update(cc.clock, nullptr); + SharedPtr ent(m_ctx.ts->get(c.getSerialNo())); + return (ent) ? ent->error() + : ZT_CERTIFICATE_ERROR_INVALID_FORMAT; // should never be null, but if so it means invalid } -ZT_ResultCode Node::deleteCertificate( - const CallContext &cc, - const void *serialNo) +ZT_ResultCode Node::deleteCertificate(const CallContext& cc, const void* serialNo) { - if (!serialNo) - return ZT_RESULT_ERROR_BAD_PARAMETER; - m_ctx.ts->erase(H384(serialNo)); - m_ctx.ts->update(-1, nullptr); - return ZT_RESULT_OK; + if (! serialNo) + return ZT_RESULT_ERROR_BAD_PARAMETER; + m_ctx.ts->erase(H384(serialNo)); + m_ctx.ts->update(-1, nullptr); + return ZT_RESULT_OK; } -struct p_certificateListInternal -{ - Vector< SharedPtr< TrustStore::Entry > > entries; - Vector< const ZT_Certificate * > c; - Vector< unsigned int > t; +struct p_certificateListInternal { + Vector > entries; + Vector c; + Vector t; }; -static void p_freeCertificateList(const void *cl) +static void p_freeCertificateList(const void* cl) { - if (cl) { - reinterpret_cast(reinterpret_cast(cl) + sizeof(ZT_CertificateList))->~p_certificateListInternal(); - free(const_cast(cl)); - } + if (cl) { + reinterpret_cast( + reinterpret_cast(cl) + sizeof(ZT_CertificateList)) + ->~p_certificateListInternal(); + free(const_cast(cl)); + } } -ZT_CertificateList *Node::listCertificates() +ZT_CertificateList* Node::listCertificates() { - ZT_CertificateList *const cl = (ZT_CertificateList *)malloc(sizeof(ZT_CertificateList) + sizeof(p_certificateListInternal)); - if (!cl) - return nullptr; + ZT_CertificateList* const cl = + (ZT_CertificateList*)malloc(sizeof(ZT_CertificateList) + sizeof(p_certificateListInternal)); + if (! cl) + return nullptr; - p_certificateListInternal *const clint = reinterpret_cast(reinterpret_cast(cl) + sizeof(ZT_CertificateList)); - new(clint) p_certificateListInternal; + p_certificateListInternal* const clint = + reinterpret_cast(reinterpret_cast(cl) + sizeof(ZT_CertificateList)); + new (clint) p_certificateListInternal; - clint->entries = m_ctx.ts->all(false); - clint->c.reserve(clint->entries.size()); - clint->t.reserve(clint->entries.size()); - for (Vector< SharedPtr< TrustStore::Entry > >::const_iterator i(clint->entries.begin()); i != clint->entries.end(); ++i) { - clint->c.push_back(&((*i)->certificate())); - clint->t.push_back((*i)->localTrust()); - } + clint->entries = m_ctx.ts->all(false); + clint->c.reserve(clint->entries.size()); + clint->t.reserve(clint->entries.size()); + for (Vector >::const_iterator i(clint->entries.begin()); i != clint->entries.end(); + ++i) { + clint->c.push_back(&((*i)->certificate())); + clint->t.push_back((*i)->localTrust()); + } - cl->freeFunction = p_freeCertificateList; - cl->certs = clint->c.data(); - cl->localTrust = clint->t.data(); - cl->certCount = (unsigned long)clint->c.size(); + cl->freeFunction = p_freeCertificateList; + cl->certs = clint->c.data(); + cl->localTrust = clint->t.data(); + cl->certCount = (unsigned long)clint->c.size(); - return cl; + return cl; } int Node::sendUserMessage( - const CallContext &cc, - uint64_t dest, - uint64_t /*typeId*/, - const void */*data*/, - unsigned int /*len*/) + const CallContext& cc, + uint64_t dest, + uint64_t /*typeId*/, + const void* /*data*/, + unsigned int /*len*/) { - try { - if (m_ctx.identity.address().toInt() != dest) { - // TODO - /* - Packet outp(Address(dest),m_ctx.identity.address(),Packet::VERB_USER_MESSAGE); - outp.append(typeId); - outp.append(data,len); - outp.compress(); - m_ctx.sw->send(tptr,outp,true); - */ - return 1; - } - } catch (...) {} - return 0; + try { + if (m_ctx.identity.address().toInt() != dest) { + // TODO + /* + Packet outp(Address(dest),m_ctx.identity.address(),Packet::VERB_USER_MESSAGE); + outp.append(typeId); + outp.append(data,len); + outp.compress(); + m_ctx.sw->send(tptr,outp,true); + */ + return 1; + } + } + catch (...) { + } + return 0; } -void Node::setController(void *networkControllerInstance) +void Node::setController(void* networkControllerInstance) { - m_ctx.localNetworkController = reinterpret_cast(networkControllerInstance); - if (networkControllerInstance) - m_ctx.localNetworkController->init(m_ctx.identity, this); + m_ctx.localNetworkController = reinterpret_cast(networkControllerInstance); + if (networkControllerInstance) + m_ctx.localNetworkController->init(m_ctx.identity, this); } -bool Node::filterPotentialPath(void *tPtr, const Identity &id, int64_t localSocket, const InetAddress &remoteAddress) +bool Node::filterPotentialPath(void* tPtr, const Identity& id, int64_t localSocket, const InetAddress& remoteAddress) { - { - Mutex::Lock l(m_allNetworks_l); - for (Vector< SharedPtr< Network > >::iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) { - for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) { - if ((*i)->config().staticIps[k].containsAddress(remoteAddress)) - return false; - } - } - } + { + Mutex::Lock l(m_allNetworks_l); + for (Vector >::iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) { + for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) { + if ((*i)->config().staticIps[k].containsAddress(remoteAddress)) + return false; + } + } + } - if (m_ctx.cb.pathCheckFunction) { - return (m_ctx.cb.pathCheckFunction( - reinterpret_cast(this), - m_ctx.uPtr, - tPtr, - id.address().toInt(), - (const ZT_Identity *)&id, - localSocket, - reinterpret_cast(&remoteAddress)) != 0); - } + if (m_ctx.cb.pathCheckFunction) { + return ( + m_ctx.cb.pathCheckFunction( + reinterpret_cast(this), + m_ctx.uPtr, + tPtr, + id.address().toInt(), + (const ZT_Identity*)&id, + localSocket, + reinterpret_cast(&remoteAddress)) + != 0); + } - return true; + return true; } -bool Node::externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr) +bool Node::externalPathLookup(void* tPtr, const Identity& id, int family, InetAddress& addr) { - if (m_ctx.cb.pathLookupFunction) { - return (m_ctx.cb.pathLookupFunction( - reinterpret_cast(this), - m_ctx.uPtr, - tPtr, - id.address().toInt(), - reinterpret_cast(&id), - family, - reinterpret_cast(&addr)) == ZT_RESULT_OK); - } - return false; + if (m_ctx.cb.pathLookupFunction) { + return ( + m_ctx.cb.pathLookupFunction( + reinterpret_cast(this), + m_ctx.uPtr, + tPtr, + id.address().toInt(), + reinterpret_cast(&id), + family, + reinterpret_cast(&addr)) + == ZT_RESULT_OK); + } + return false; } // Implementation of NetworkController::Sender ------------------------------------------------------------------------ -void Node::ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig) +void Node::ncSendConfig( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + const NetworkConfig& nc, + bool sendLegacyFormatConfig) { - if (destination == m_ctx.identity.address()) { - SharedPtr< Network > n(m_ctx.networks->get(nwid)); - if (!n) - return; - CallContext cc(clock, ticks, tPtr); - n->setConfiguration(cc, nc, true); - } else { - Dictionary dconf; - if (nc.toDictionary(dconf)) { - uint64_t configUpdateId = Utils::random(); - if (!configUpdateId) - ++configUpdateId; + if (destination == m_ctx.identity.address()) { + SharedPtr n(m_ctx.networks->get(nwid)); + if (! n) + return; + CallContext cc(clock, ticks, tPtr); + n->setConfiguration(cc, nc, true); + } + else { + Dictionary dconf; + if (nc.toDictionary(dconf)) { + uint64_t configUpdateId = Utils::random(); + if (! configUpdateId) + ++configUpdateId; - Vector< uint8_t > ddata; - dconf.encode(ddata); - // TODO - /* - unsigned int chunkIndex = 0; - while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); - Packet outp(destination,m_ctx.identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); - if (requestPacketId) { - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - } + Vector ddata; + dconf.encode(ddata); + // TODO + /* + unsigned int chunkIndex = 0; + while (chunkIndex < totalSize) { + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH + - (ZT_PACKET_IDX_PAYLOAD + 256))); Packet outp(destination,m_ctx.identity.address(),(requestPacketId) ? + Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); if (requestPacketId) { outp.append((unsigned + char)Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append(requestPacketId); + } - const unsigned int sigStart = outp.size(); - outp.append(nwid); - outp.append((uint16_t)chunkLen); - outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); + const unsigned int sigStart = outp.size(); + outp.append(nwid); + outp.append((uint16_t)chunkLen); + outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); - outp.append((uint8_t)0); // no flags - outp.append((uint64_t)configUpdateId); - outp.append((uint32_t)totalSize); - outp.append((uint32_t)chunkIndex); + outp.append((uint8_t)0); // no flags + outp.append((uint64_t)configUpdateId); + outp.append((uint32_t)totalSize); + outp.append((uint32_t)chunkIndex); - uint8_t sig[256]; - const unsigned int siglen = m_ctx.identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig)); - outp.append((uint8_t)1); - outp.append((uint16_t)siglen); - outp.append(sig,siglen); + uint8_t sig[256]; + const unsigned int siglen = m_ctx.identity.sign(reinterpret_cast(outp.data()) + + sigStart,outp.size() - sigStart,sig,sizeof(sig)); outp.append((uint8_t)1); outp.append((uint16_t)siglen); + outp.append(sig,siglen); - outp.compress(); - m_ctx.sw->send((void *)0,outp,true); - chunkIndex += chunkLen; - } - */ - } - } + outp.compress(); + m_ctx.sw->send((void *)0,outp,true); + chunkIndex += chunkLen; + } + */ + } + } } -void Node::ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev) +void Node::ncSendRevocation( + void* tPtr, + int64_t clock, + int64_t ticks, + const Address& destination, + const RevocationCredential& rev) { - if (destination == m_ctx.identity.address()) { - SharedPtr< Network > n(m_ctx.networks->get(rev.networkId())); - if (!n) - return; - CallContext cc(clock, ticks, tPtr); - n->addCredential(cc, m_ctx.identity, rev); - } else { - // TODO - /* - Packet outp(destination,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); - outp.append((uint16_t)0); - outp.append((uint16_t)1); - rev.serialize(outp); - outp.append((uint16_t)0); - m_ctx.sw->send((void *)0,outp,true); - */ - } + if (destination == m_ctx.identity.address()) { + SharedPtr n(m_ctx.networks->get(rev.networkId())); + if (! n) + return; + CallContext cc(clock, ticks, tPtr); + n->addCredential(cc, m_ctx.identity, rev); + } + else { + // TODO + /* + Packet outp(destination,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + outp.append((uint8_t)0x00); + outp.append((uint16_t)0); + outp.append((uint16_t)0); + outp.append((uint16_t)1); + rev.serialize(outp); + outp.append((uint16_t)0); + m_ctx.sw->send((void *)0,outp,true); + */ + } } -void Node::ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode) +void Node::ncSendError( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + NetworkController::ErrorCode errorCode) { - if (destination == m_ctx.identity.address()) { - SharedPtr< Network > n(m_ctx.networks->get(nwid)); - if (!n) - return; - switch (errorCode) { - case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - n->setNotFound(); - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - n->setAccessDenied(); - break; + if (destination == m_ctx.identity.address()) { + SharedPtr n(m_ctx.networks->get(nwid)); + if (! n) + return; + switch (errorCode) { + case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + n->setNotFound(); + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + n->setAccessDenied(); + break; - default: - break; - } - } else if (requestPacketId) { - // TODO - /* - Packet outp(destination,m_ctx.identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - switch(errorCode) { - //case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - //case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - default: - outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); - break; - } - outp.append(nwid); - m_ctx.sw->send((void *)0,outp,true); - */ - } // else we can't send an ERROR() in response to nothing, so discard + default: + break; + } + } + else if (requestPacketId) { + // TODO + /* + Packet outp(destination,m_ctx.identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + switch(errorCode) { + //case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + //case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + default: + outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); + break; + } + outp.append(nwid); + m_ctx.sw->send((void *)0,outp,true); + */ + } // else we can't send an ERROR() in response to nothing, so discard } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Node.hpp b/core/Node.hpp index 1ecd36d95..3e796740c 100644 --- a/core/Node.hpp +++ b/core/Node.hpp @@ -14,19 +14,19 @@ #ifndef ZT_NODE_HPP #define ZT_NODE_HPP +#include "Buf.hpp" +#include "CallContext.hpp" #include "Constants.hpp" +#include "Containers.hpp" #include "Context.hpp" #include "InetAddress.hpp" -#include "Mutex.hpp" #include "MAC.hpp" +#include "Mutex.hpp" #include "Network.hpp" +#include "NetworkController.hpp" #include "Path.hpp" #include "Salsa20.hpp" -#include "NetworkController.hpp" -#include "Buf.hpp" -#include "Containers.hpp" #include "Store.hpp" -#include "CallContext.hpp" namespace ZeroTier { @@ -35,167 +35,170 @@ namespace ZeroTier { * * The pointer returned by ZT_Node_new() is an instance of this class. */ -class Node : public NetworkController::Sender -{ -public: - // Get rid of alignment warnings on 32-bit Windows +class Node : public NetworkController::Sender { + public: + // Get rid of alignment warnings on 32-bit Windows #ifdef __WINDOWS__ - void * operator new(size_t i) { return _mm_malloc(i,16); } - void operator delete(void* p) { _mm_free(p); } + void* operator new(size_t i) + { + return _mm_malloc(i, 16); + } + void operator delete(void* p) + { + _mm_free(p); + } #endif - Node(void *uPtr, const struct ZT_Node_Callbacks *callbacks, const CallContext &cc); + Node(void* uPtr, const struct ZT_Node_Callbacks* callbacks, const CallContext& cc); - virtual ~Node(); + virtual ~Node(); - void shutdown(const CallContext &cc); + void shutdown(const CallContext& cc); - ZT_ResultCode processBackgroundTasks( - const CallContext &cc, - volatile int64_t *nextBackgroundTaskDeadline); + ZT_ResultCode processBackgroundTasks(const CallContext& cc, volatile int64_t* nextBackgroundTaskDeadline); - ZT_ResultCode join( - uint64_t nwid, - const ZT_Fingerprint *controllerFingerprint, - void *uptr, - const CallContext &cc); + ZT_ResultCode join(uint64_t nwid, const ZT_Fingerprint* controllerFingerprint, void* uptr, const CallContext& cc); - ZT_ResultCode leave( - uint64_t nwid, - void **uptr, - const CallContext &cc); + ZT_ResultCode leave(uint64_t nwid, void** uptr, const CallContext& cc); - ZT_ResultCode multicastSubscribe( - const CallContext &cc, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi); + ZT_ResultCode + multicastSubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); - ZT_ResultCode multicastUnsubscribe( - const CallContext &cc, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi); + ZT_ResultCode + multicastUnsubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); - void status( - ZT_NodeStatus *status) const; + void status(ZT_NodeStatus* status) const; - ZT_PeerList *peers( - const CallContext &cc) const; + ZT_PeerList* peers(const CallContext& cc) const; - ZT_VirtualNetworkConfig *networkConfig( - uint64_t nwid) const; + ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const; - ZT_VirtualNetworkList *networks() const; + ZT_VirtualNetworkList* networks() const; - void setNetworkUserPtr( - uint64_t nwid, - void *ptr); + void setNetworkUserPtr(uint64_t nwid, void* ptr); - void setInterfaceAddresses( - const ZT_InterfaceAddress *addrs, - unsigned int addrCount); + void setInterfaceAddresses(const ZT_InterfaceAddress* addrs, unsigned int addrCount); - ZT_CertificateError addCertificate( - const CallContext &cc, - unsigned int localTrust, - const ZT_Certificate *cert, - const void *certData, - unsigned int certSize); + ZT_CertificateError addCertificate( + const CallContext& cc, + unsigned int localTrust, + const ZT_Certificate* cert, + const void* certData, + unsigned int certSize); - ZT_ResultCode deleteCertificate( - const CallContext &cc, - const void *serialNo); + ZT_ResultCode deleteCertificate(const CallContext& cc, const void* serialNo); - ZT_CertificateList *listCertificates(); + ZT_CertificateList* listCertificates(); - int sendUserMessage( - const CallContext &cc, - uint64_t dest, - uint64_t typeId, - const void *data, - unsigned int len); + int sendUserMessage(const CallContext& cc, uint64_t dest, uint64_t typeId, const void* data, unsigned int len); - void setController( - void *networkControllerInstance); + void setController(void* networkControllerInstance); - /** - * Post an event via external callback - * - * @param tPtr Thread pointer - * @param ev Event object - * @param md Event data or NULL if none - * @param mdSize Size of event data - */ - ZT_INLINE void postEvent(void *const tPtr, const ZT_Event ev, const void *const md = nullptr, const unsigned int mdSize = 0) noexcept - { m_ctx.cb.eventCallback(reinterpret_cast(this), m_ctx.uPtr, tPtr, ev, md, mdSize); } + /** + * Post an event via external callback + * + * @param tPtr Thread pointer + * @param ev Event object + * @param md Event data or NULL if none + * @param mdSize Size of event data + */ + ZT_INLINE void + postEvent(void* const tPtr, const ZT_Event ev, const void* const md = nullptr, const unsigned int mdSize = 0) + noexcept + { + m_ctx.cb.eventCallback(reinterpret_cast(this), m_ctx.uPtr, tPtr, ev, md, mdSize); + } - /** - * Check whether a path should be used for ZeroTier traffic - * - * This performs internal checks and also calls out to an external callback if one is defined. - * - * @param tPtr Thread pointer - * @param id Identity of peer - * @param localSocket Local socket or -1 if unknown - * @param remoteAddress Remote address - * @return True if path should be used - */ - bool filterPotentialPath(void *tPtr, const Identity &id, int64_t localSocket, const InetAddress &remoteAddress); + /** + * Check whether a path should be used for ZeroTier traffic + * + * This performs internal checks and also calls out to an external callback if one is defined. + * + * @param tPtr Thread pointer + * @param id Identity of peer + * @param localSocket Local socket or -1 if unknown + * @param remoteAddress Remote address + * @return True if path should be used + */ + bool filterPotentialPath(void* tPtr, const Identity& id, int64_t localSocket, const InetAddress& remoteAddress); - /** - * Query callback for a physical address for a peer - * - * @param tPtr Thread pointer - * @param id Full identity of ZeroTier node - * @param family Desired address family or -1 for any - * @param addr Buffer to store address (result paramter) - * @return True if addr was filled with something - */ - bool externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr); + /** + * Query callback for a physical address for a peer + * + * @param tPtr Thread pointer + * @param id Full identity of ZeroTier node + * @param family Desired address family or -1 for any + * @param addr Buffer to store address (result paramter) + * @return True if addr was filled with something + */ + bool externalPathLookup(void* tPtr, const Identity& id, int family, InetAddress& addr); - ZT_INLINE const Identity &identity() const noexcept - { return m_ctx.identity; } + ZT_INLINE const Identity& identity() const noexcept + { + return m_ctx.identity; + } - ZT_INLINE const Context &context() const noexcept - { return m_ctx; } + ZT_INLINE const Context& context() const noexcept + { + return m_ctx; + } - // Implementation of NetworkController::Sender interface - virtual void ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig); - virtual void ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev); - virtual void ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode); + // Implementation of NetworkController::Sender interface + virtual void ncSendConfig( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + const NetworkConfig& nc, + bool sendLegacyFormatConfig); + virtual void ncSendRevocation( + void* tPtr, + int64_t clock, + int64_t ticks, + const Address& destination, + const RevocationCredential& rev); + virtual void ncSendError( + void* tPtr, + int64_t clock, + int64_t ticks, + uint64_t nwid, + uint64_t requestPacketId, + const Address& destination, + NetworkController::ErrorCode errorCode); -private: - Context m_ctx; + private: + Context m_ctx; - // Data store wrapper - Store m_store; + // Data store wrapper + Store m_store; - // Pointer to a struct defined in Node that holds instances of core objects. - void *m_objects; + // Pointer to a struct defined in Node that holds instances of core objects. + void* m_objects; - // This stores networks for rapid iteration, while RR->networks is the primary lookup. - Vector< SharedPtr< Network > > m_allNetworks; - Mutex m_allNetworks_l; + // This stores networks for rapid iteration, while RR->networks is the primary lookup. + Vector > m_allNetworks; + Mutex m_allNetworks_l; - // These are local interface addresses that have been configured via the API - // and can be pushed to other nodes. - Vector< ZT_InterfaceAddress > m_localInterfaceAddresses; - Mutex m_localInterfaceAddresses_m; + // These are local interface addresses that have been configured via the API + // and can be pushed to other nodes. + Vector m_localInterfaceAddresses; + Mutex m_localInterfaceAddresses_m; - // This is locked while running processBackgroundTasks(). - Mutex m_backgroundTasksLock; + // This is locked while running processBackgroundTasks(). + Mutex m_backgroundTasksLock; - // These are locked via _backgroundTasksLock as they're only checked and modified in processBackgroundTasks(). - int64_t m_lastPeerPulse; - int64_t m_lastHousekeepingRun; - int64_t m_lastNetworkHousekeepingRun; - int64_t m_lastTrustStoreUpdate; + // These are locked via _backgroundTasksLock as they're only checked and modified in processBackgroundTasks(). + int64_t m_lastPeerPulse; + int64_t m_lastHousekeepingRun; + int64_t m_lastNetworkHousekeepingRun; + int64_t m_lastTrustStoreUpdate; - // True if at least one root appears reachable. - std::atomic< bool > m_online; + // True if at least one root appears reachable. + std::atomic m_online; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/OS.hpp b/core/OS.hpp index 3d0f6b376..c60d1e11d 100644 --- a/core/OS.hpp +++ b/core/OS.hpp @@ -17,7 +17,9 @@ /* Uncomment this to force a whole lot of debug output. */ #define ZT_DEBUG_SPEW -#if !defined(__GNUC__) && (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)) +#if ! defined(__GNUC__) \ + && (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)) #define __GNUC__ 3 #endif @@ -48,46 +50,50 @@ #undef __BSD__ #endif +#include #include -#include #include #include #include -#include #include +#include #endif /* Microsoft Windows */ #ifndef __WINDOWS__ #include #include -#include #include +#include #endif /* NOT Microsoft Windows */ #include +#include #include #include -#include -#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) +#if ( \ + defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) \ + || defined(__AMD64__) || defined(_M_X64)) #define ZT_ARCH_X64 1 -#include #include #include +#include #endif -#if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386) +#if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) \ + || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) \ + || defined(__I86__) || defined(__INTEL__) || defined(__386) #define ZT_ARCH_X86 1 #endif -#if !defined(ZT_ARCH_X86) +#if ! defined(ZT_ARCH_X86) #ifndef ZT_NO_UNALIGNED_ACCESS #define ZT_NO_UNALIGNED_ACCESS 1 #endif #endif #if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON) -#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) +#if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) #ifdef ZT_ARCH_ARM_HAS_NEON #undef ZT_ARCH_ARM_HAS_NEON #endif @@ -110,8 +116,8 @@ #define __BSD__ 1 #endif #ifndef __BYTE_ORDER -#define __BYTE_ORDER __DARWIN_BYTE_ORDER -#define __BIG_ENDIAN __DARWIN_BIG_ENDIAN +#define __BYTE_ORDER __DARWIN_BYTE_ORDER +#define __BIG_ENDIAN __DARWIN_BIG_ENDIAN #define __LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN #endif #endif @@ -140,13 +146,13 @@ #endif #ifdef __WINDOWS__ -#define ZT_PATH_SEPARATOR '\\' +#define ZT_PATH_SEPARATOR '\\' #define ZT_PATH_SEPARATOR_S "\\" -#define ZT_EOL_S "\r\n" +#define ZT_EOL_S "\r\n" #else -#define ZT_PATH_SEPARATOR '/' +#define ZT_PATH_SEPARATOR '/' #define ZT_PATH_SEPARATOR_S "/" -#define ZT_EOL_S "\n" +#define ZT_EOL_S "\n" #endif #ifdef SOCKET @@ -208,9 +214,9 @@ * if a shim for were included. */ #ifndef __CPP11__ #error TODO: to build on pre-c++11 compilers we will need to make a subset of std::atomic for integers -#define nullptr (0) +#define nullptr (0) #define constexpr ZT_INLINE -#define noexcept throw() +#define noexcept throw() #define explicit #endif #endif @@ -225,7 +231,7 @@ #ifndef likely #if defined(__GNUC__) || defined(__clang__) -#define likely(x) __builtin_expect((x),1) +#define likely(x) __builtin_expect((x), 1) #else #define likely(x) x #endif @@ -233,7 +239,7 @@ #ifndef unlikely #if defined(__GNUC__) || defined(__clang__) -#define unlikely(x) __builtin_expect((x),0) +#define unlikely(x) __builtin_expect((x), 0) #else #define unlikely(x) x #endif @@ -249,28 +255,29 @@ typedef unsigned uint128_t __attribute__((mode(TI))); #endif #endif -#if !defined(__BYTE_ORDER) && defined(__BYTE_ORDER__) -#define __BYTE_ORDER __BYTE_ORDER__ +#if ! defined(__BYTE_ORDER) && defined(__BYTE_ORDER__) +#define __BYTE_ORDER __BYTE_ORDER__ #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ -#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ #endif -#if !defined(__BYTE_ORDER) && defined(BYTE_ORDER) -#define __BYTE_ORDER BYTE_ORDER +#if ! defined(__BYTE_ORDER) && defined(BYTE_ORDER) +#define __BYTE_ORDER BYTE_ORDER #define __LITTLE_ENDIAN LITTLE_ENDIAN -#define __BIG_ENDIAN BIG_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN #endif -#if !defined(__BYTE_ORDER) && defined(_BYTE_ORDER) -#define __BYTE_ORDER _BYTE_ORDER +#if ! defined(__BYTE_ORDER) && defined(_BYTE_ORDER) +#define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN #endif #define ZT_VA_ARGS(...) , ##__VA_ARGS__ #ifdef ZT_DEBUG_SPEW -#define ZT_SPEW(f,...) fprintf(stderr,"%s:%d(%s): " f ZT_EOL_S,__FILE__,__LINE__,__FUNCTION__ ZT_VA_ARGS(__VA_ARGS__)) +#define ZT_SPEW(f, ...) \ + fprintf(stderr, "%s:%d(%s): " f ZT_EOL_S, __FILE__, __LINE__, __FUNCTION__ ZT_VA_ARGS(__VA_ARGS__)) #else -#define ZT_SPEW(f,...) +#define ZT_SPEW(f, ...) #endif #endif diff --git a/core/OwnershipCredential.cpp b/core/OwnershipCredential.cpp index 4fb0f7a80..07aadec32 100644 --- a/core/OwnershipCredential.cpp +++ b/core/OwnershipCredential.cpp @@ -15,112 +15,117 @@ namespace ZeroTier { -void OwnershipCredential::addThing(const InetAddress &ip) +void OwnershipCredential::addThing(const InetAddress& ip) { - if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) - return; - if (ip.as.sa.sa_family == AF_INET) { - m_thingTypes[m_thingCount] = THING_IPV4_ADDRESS; - Utils::copy<4>(m_thingValues[m_thingCount], &(reinterpret_cast(&ip)->sin_addr.s_addr)); - ++m_thingCount; - } else if (ip.as.sa.sa_family == AF_INET6) { - m_thingTypes[m_thingCount] = THING_IPV6_ADDRESS; - Utils::copy<16>(m_thingValues[m_thingCount], reinterpret_cast(&ip)->sin6_addr.s6_addr); - ++m_thingCount; - } + if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + return; + if (ip.as.sa.sa_family == AF_INET) { + m_thingTypes[m_thingCount] = THING_IPV4_ADDRESS; + Utils::copy<4>( + m_thingValues[m_thingCount], + &(reinterpret_cast(&ip)->sin_addr.s_addr)); + ++m_thingCount; + } + else if (ip.as.sa.sa_family == AF_INET6) { + m_thingTypes[m_thingCount] = THING_IPV6_ADDRESS; + Utils::copy<16>( + m_thingValues[m_thingCount], + reinterpret_cast(&ip)->sin6_addr.s6_addr); + ++m_thingCount; + } } -void OwnershipCredential::addThing(const MAC &mac) +void OwnershipCredential::addThing(const MAC& mac) { - if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) - return; - m_thingTypes[m_thingCount] = THING_MAC_ADDRESS; - mac.copyTo(m_thingValues[m_thingCount]); - ++m_thingCount; + if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + return; + m_thingTypes[m_thingCount] = THING_MAC_ADDRESS; + mac.copyTo(m_thingValues[m_thingCount]); + ++m_thingCount; } -bool OwnershipCredential::sign(const Identity &signer) +bool OwnershipCredential::sign(const Identity& signer) { - uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16]; - if (signer.hasPrivate()) { - m_signedBy = signer.address(); - m_signatureLength = signer.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature)); - return true; - } - return false; + uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16]; + if (signer.hasPrivate()) { + m_signedBy = signer.address(); + m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); + return true; + } + return false; } int OwnershipCredential::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign) const noexcept { - int p = 0; - if (forSign) { - for (int k = 0;k < 16;++k) - data[p++] = 0x7f; - } - Utils::storeBigEndian(data + p, m_networkId); - Utils::storeBigEndian(data + p + 8, (uint64_t) m_ts); - Utils::storeBigEndian(data + p + 16, m_flags); - Utils::storeBigEndian(data + p + 24, m_id); - Utils::storeBigEndian(data + p + 28, (uint16_t) m_thingCount); - p += 30; - for (unsigned int i = 0, j = m_thingCount;i < j;++i) { - data[p++] = m_thingTypes[i]; - Utils::copy(data + p, m_thingValues[i]); - p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; - } - m_issuedTo.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - m_signedBy.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - if (!forSign) { - data[p++] = 1; - Utils::storeBigEndian(data + p, (uint16_t) m_signatureLength); - p += 2; - Utils::copy(data + p, m_signature, m_signatureLength); - p += (int) m_signatureLength; - } - data[p++] = 0; - data[p++] = 0; - if (forSign) { - for (int k = 0;k < 16;++k) - data[p++] = 0x7f; - } - return p; + int p = 0; + if (forSign) { + for (int k = 0; k < 16; ++k) + data[p++] = 0x7f; + } + Utils::storeBigEndian(data + p, m_networkId); + Utils::storeBigEndian(data + p + 8, (uint64_t)m_ts); + Utils::storeBigEndian(data + p + 16, m_flags); + Utils::storeBigEndian(data + p + 24, m_id); + Utils::storeBigEndian(data + p + 28, (uint16_t)m_thingCount); + p += 30; + for (unsigned int i = 0, j = m_thingCount; i < j; ++i) { + data[p++] = m_thingTypes[i]; + Utils::copy(data + p, m_thingValues[i]); + p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; + } + m_issuedTo.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + m_signedBy.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + if (! forSign) { + data[p++] = 1; + Utils::storeBigEndian(data + p, (uint16_t)m_signatureLength); + p += 2; + Utils::copy(data + p, m_signature, m_signatureLength); + p += (int)m_signatureLength; + } + data[p++] = 0; + data[p++] = 0; + if (forSign) { + for (int k = 0; k < 16; ++k) + data[p++] = 0x7f; + } + return p; } -int OwnershipCredential::unmarshal(const uint8_t *data, int len) noexcept +int OwnershipCredential::unmarshal(const uint8_t* data, int len) noexcept { - if (len < 30) - return -1; + if (len < 30) + return -1; - m_networkId = Utils::loadBigEndian(data); - m_ts = (int64_t) Utils::loadBigEndian(data + 8); - m_flags = Utils::loadBigEndian(data + 16); - m_id = Utils::loadBigEndian(data + 24); - m_thingCount = Utils::loadBigEndian(data + 28); - if (m_thingCount > ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) - return -1; - int p = 30; + m_networkId = Utils::loadBigEndian(data); + m_ts = (int64_t)Utils::loadBigEndian(data + 8); + m_flags = Utils::loadBigEndian(data + 16); + m_id = Utils::loadBigEndian(data + 24); + m_thingCount = Utils::loadBigEndian(data + 28); + if (m_thingCount > ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + return -1; + int p = 30; - for (unsigned int i = 0, j = m_thingCount;i < j;++i) { - if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len) - return -1; - m_thingTypes[i] = data[p++]; - Utils::copy(m_thingValues[i], data + p); - p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; - } + for (unsigned int i = 0, j = m_thingCount; i < j; ++i) { + if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len) + return -1; + m_thingTypes[i] = data[p++]; + Utils::copy(m_thingValues[i], data + p); + p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; + } - if ((p + ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH + 1 + 2) > len) - return -1; - m_issuedTo.setTo(data + p); - p += ZT_ADDRESS_LENGTH; - m_signedBy.setTo(data + p); - p += ZT_ADDRESS_LENGTH + 1; + if ((p + ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH + 1 + 2) > len) + return -1; + m_issuedTo.setTo(data + p); + p += ZT_ADDRESS_LENGTH; + m_signedBy.setTo(data + p); + p += ZT_ADDRESS_LENGTH + 1; - p += 2 + Utils::loadBigEndian(data + p); - if (p > len) - return -1; - return p; + p += 2 + Utils::loadBigEndian(data + p); + if (p > len) + return -1; + return p; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/OwnershipCredential.hpp b/core/OwnershipCredential.hpp index f36809fb1..d7d98704d 100644 --- a/core/OwnershipCredential.hpp +++ b/core/OwnershipCredential.hpp @@ -14,10 +14,10 @@ #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #define ZT_CERTIFICATEOFOWNERSHIP_HPP +#include "Address.hpp" +#include "C25519.hpp" #include "Constants.hpp" #include "Credential.hpp" -#include "C25519.hpp" -#include "Address.hpp" #include "Identity.hpp" #include "InetAddress.hpp" #include "MAC.hpp" @@ -28,7 +28,9 @@ // Maximum size of a thing's value field in bytes #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16 -#define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX (8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) +#define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX \ + (8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) \ + + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) namespace ZeroTier { @@ -40,164 +42,201 @@ class Context; * These are used in conjunction with the rules engine to make IP addresses and * other identifiers un-spoofable. */ -class OwnershipCredential : public Credential -{ - friend class Credential; +class OwnershipCredential : public Credential { + friend class Credential; -public: - static constexpr ZT_CredentialType credentialType() noexcept - { return ZT_CREDENTIAL_TYPE_COO; } + public: + static constexpr ZT_CredentialType credentialType() noexcept + { + return ZT_CREDENTIAL_TYPE_COO; + } - enum Thing - { - THING_NULL = 0, - THING_MAC_ADDRESS = 1, - THING_IPV4_ADDRESS = 2, - THING_IPV6_ADDRESS = 3 - }; + enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 }; - ZT_INLINE OwnershipCredential() noexcept - { memoryZero(this); } + ZT_INLINE OwnershipCredential() noexcept + { + memoryZero(this); + } - ZT_INLINE OwnershipCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id) noexcept - { - memoryZero(this); - m_networkId = nwid; - m_ts = ts; - m_id = id; - m_issuedTo = issuedTo; - } + ZT_INLINE + OwnershipCredential(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id) noexcept + { + memoryZero(this); + m_networkId = nwid; + m_ts = ts; + m_id = id; + m_issuedTo = issuedTo; + } - ZT_INLINE uint64_t networkId() const noexcept - { return m_networkId; } + ZT_INLINE uint64_t networkId() const noexcept + { + return m_networkId; + } - ZT_INLINE int64_t timestamp() const noexcept - { return m_ts; } + ZT_INLINE int64_t timestamp() const noexcept + { + return m_ts; + } - ZT_INLINE int64_t revision() const noexcept - { return m_ts; } + ZT_INLINE int64_t revision() const noexcept + { + return m_ts; + } - ZT_INLINE uint32_t id() const noexcept - { return m_id; } + ZT_INLINE uint32_t id() const noexcept + { + return m_id; + } - ZT_INLINE const Address &issuedTo() const noexcept - { return m_issuedTo; } + ZT_INLINE const Address& issuedTo() const noexcept + { + return m_issuedTo; + } - ZT_INLINE const Address &signer() const noexcept - { return m_signedBy; } + ZT_INLINE const Address& signer() const noexcept + { + return m_signedBy; + } - ZT_INLINE const uint8_t *signature() const noexcept - { return m_signature; } + ZT_INLINE const uint8_t* signature() const noexcept + { + return m_signature; + } - ZT_INLINE unsigned int signatureLength() const noexcept - { return m_signatureLength; } + ZT_INLINE unsigned int signatureLength() const noexcept + { + return m_signatureLength; + } - ZT_INLINE unsigned int thingCount() const noexcept - { return (unsigned int)m_thingCount; } + ZT_INLINE unsigned int thingCount() const noexcept + { + return (unsigned int)m_thingCount; + } - ZT_INLINE Thing thingType(const unsigned int i) const noexcept - { return (Thing)m_thingTypes[i]; } + ZT_INLINE Thing thingType(const unsigned int i) const noexcept + { + return (Thing)m_thingTypes[i]; + } - ZT_INLINE const uint8_t *thingValue(const unsigned int i) const noexcept - { return m_thingValues[i]; } + ZT_INLINE const uint8_t* thingValue(const unsigned int i) const noexcept + { + return m_thingValues[i]; + } - ZT_INLINE bool owns(const InetAddress &ip) const noexcept - { - if (ip.as.sa.sa_family == AF_INET) - return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast(&ip)->sin_addr.s_addr), 4); - else if (ip.as.sa.sa_family == AF_INET6) - return this->_owns(THING_IPV6_ADDRESS, reinterpret_cast(&ip)->sin6_addr.s6_addr, 16); - else return false; - } + ZT_INLINE bool owns(const InetAddress& ip) const noexcept + { + if (ip.as.sa.sa_family == AF_INET) + return this->_owns( + THING_IPV4_ADDRESS, + &(reinterpret_cast(&ip)->sin_addr.s_addr), + 4); + else if (ip.as.sa.sa_family == AF_INET6) + return this->_owns( + THING_IPV6_ADDRESS, + reinterpret_cast(&ip)->sin6_addr.s6_addr, + 16); + else + return false; + } - ZT_INLINE bool owns(const MAC &mac) const noexcept - { - uint8_t tmp[6]; - mac.copyTo(tmp); - return this->_owns(THING_MAC_ADDRESS, tmp, 6); - } + ZT_INLINE bool owns(const MAC& mac) const noexcept + { + uint8_t tmp[6]; + mac.copyTo(tmp); + return this->_owns(THING_MAC_ADDRESS, tmp, 6); + } - /** - * Add an IP address to this certificate - * - * @param ip IPv4 or IPv6 address - */ - void addThing(const InetAddress &ip); + /** + * Add an IP address to this certificate + * + * @param ip IPv4 or IPv6 address + */ + void addThing(const InetAddress& ip); - /** - * Add an Ethernet MAC address - * - * ZeroTier MAC addresses are always un-spoofable. This could in theory be - * used to make bridged MAC addresses un-spoofable as well, but it's not - * currently implemented. - * - * @param mac 48-bit MAC address - */ - void addThing(const MAC &mac); + /** + * Add an Ethernet MAC address + * + * ZeroTier MAC addresses are always un-spoofable. This could in theory be + * used to make bridged MAC addresses un-spoofable as well, but it's not + * currently implemented. + * + * @param mac 48-bit MAC address + */ + void addThing(const MAC& mac); - /** - * Sign this certificate - * - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - bool sign(const Identity &signer); + /** + * Sign this certificate + * + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + bool sign(const Identity& signer); - /** - * Verify certificate signature - * - * @return Credential verification result: OK, bad signature, or identity needed - */ - ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const - { return s_verify(ctx, cc, *this); } + /** + * Verify certificate signature + * + * @return Credential verification result: OK, bad signature, or identity needed + */ + ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const + { + return s_verify(ctx, cc, *this); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; - // Provides natural sort order by ID - ZT_INLINE bool operator<(const OwnershipCredential &coo) const noexcept - { return (m_id < coo.m_id); } + // Provides natural sort order by ID + ZT_INLINE bool operator<(const OwnershipCredential& coo) const noexcept + { + return (m_id < coo.m_id); + } - ZT_INLINE bool operator==(const OwnershipCredential &coo) const noexcept - { return (memcmp(this, &coo, sizeof(OwnershipCredential)) == 0); } + ZT_INLINE bool operator==(const OwnershipCredential& coo) const noexcept + { + return (memcmp(this, &coo, sizeof(OwnershipCredential)) == 0); + } - ZT_INLINE bool operator!=(const OwnershipCredential &coo) const noexcept - { return (memcmp(this, &coo, sizeof(OwnershipCredential)) != 0); } + ZT_INLINE bool operator!=(const OwnershipCredential& coo) const noexcept + { + return (memcmp(this, &coo, sizeof(OwnershipCredential)) != 0); + } -private: - ZT_INLINE bool _owns(const Thing &t, const void *v, unsigned int l) const noexcept - { - for (unsigned int i = 0, j = m_thingCount; i < j; ++i) { - if (m_thingTypes[i] == (uint8_t)t) { - unsigned int k = 0; - while (k < l) { - if (reinterpret_cast(v)[k] != m_thingValues[i][k]) - break; - ++k; - } - if (k == l) - return true; - } - } - return false; - } + private: + ZT_INLINE bool _owns(const Thing& t, const void* v, unsigned int l) const noexcept + { + for (unsigned int i = 0, j = m_thingCount; i < j; ++i) { + if (m_thingTypes[i] == (uint8_t)t) { + unsigned int k = 0; + while (k < l) { + if (reinterpret_cast(v)[k] != m_thingValues[i][k]) + break; + ++k; + } + if (k == l) + return true; + } + } + return false; + } - uint64_t m_networkId; - int64_t m_ts; - uint64_t m_flags; - uint32_t m_id; - uint16_t m_thingCount; - uint8_t m_thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; - uint8_t m_thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; - Address m_issuedTo; - Address m_signedBy; - unsigned int m_signatureLength; - uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; + uint64_t m_networkId; + int64_t m_ts; + uint64_t m_flags; + uint32_t m_id; + uint16_t m_thingCount; + uint8_t m_thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; + uint8_t m_thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; + Address m_issuedTo; + Address m_signedBy; + unsigned int m_signatureLength; + uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Path.cpp b/core/Path.cpp index e93919b49..5dd4dd750 100644 --- a/core/Path.cpp +++ b/core/Path.cpp @@ -12,19 +12,30 @@ /****/ #include "Path.hpp" + #include "Context.hpp" #include "Node.hpp" namespace ZeroTier { -bool Path::send(const Context &ctx, const CallContext &cc, const void *const data, const unsigned int len) noexcept +bool Path::send(const Context& ctx, const CallContext& cc, const void* const data, const unsigned int len) noexcept { - if (likely(ctx.cb.wirePacketSendFunction(reinterpret_cast(ctx.node), ctx.uPtr, cc.tPtr, m_localSocket, reinterpret_cast(&m_addr), data, len, 0) == 0)) { - m_lastOut = cc.ticks; - m_outMeter.log(cc.ticks, len); - return true; - } - return false; + if (likely( + ctx.cb.wirePacketSendFunction( + reinterpret_cast(ctx.node), + ctx.uPtr, + cc.tPtr, + m_localSocket, + reinterpret_cast(&m_addr), + data, + len, + 0) + == 0)) { + m_lastOut = cc.ticks; + m_outMeter.log(cc.ticks, len); + return true; + } + return false; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Path.hpp b/core/Path.hpp index 557d5c09c..3ad49b690 100644 --- a/core/Path.hpp +++ b/core/Path.hpp @@ -14,219 +14,249 @@ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP +#include "CallContext.hpp" #include "Constants.hpp" +#include "Containers.hpp" #include "InetAddress.hpp" +#include "Meter.hpp" +#include "Mutex.hpp" #include "SharedPtr.hpp" #include "Utils.hpp" -#include "Mutex.hpp" -#include "Meter.hpp" -#include "Containers.hpp" -#include "CallContext.hpp" namespace ZeroTier { class Context; -template< unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P > -class Defragmenter; +template class Defragmenter; /** * A path across the physical network */ -class Path -{ - friend class SharedPtr< Path >; +class Path { + friend class SharedPtr; - // Allow defragmenter to access fragment-in-flight info stored in Path for performance reasons. - template< unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P > - friend - class Defragmenter; + // Allow defragmenter to access fragment-in-flight info stored in Path for performance reasons. + template + friend class Defragmenter; -public: - /** - * Map key for paths designed for very fast lookup - */ - class Key - { - public: - ZT_INLINE Key() noexcept - {} + public: + /** + * Map key for paths designed for very fast lookup + */ + class Key { + public: + ZT_INLINE Key() noexcept + { + } - ZT_INLINE Key(const InetAddress &ip) noexcept - { - const unsigned int family = ip.as.sa.sa_family; - if (family == AF_INET) { - const uint16_t p = (uint16_t)ip.as.sa_in.sin_port; - m_hashCode = Utils::hash64((((uint64_t)ip.as.sa_in.sin_addr.s_addr) << 16U) ^ ((uint64_t)p) ^ Utils::s_mapNonce); - m_ipv6Net64 = 0; // 0 for IPv4, never 0 for IPv6 - m_port = p; - } else { - if (likely(family == AF_INET6)) { - const uint64_t a = Utils::loadMachineEndian< uint64_t >(reinterpret_cast(ip.as.sa_in6.sin6_addr.s6_addr)); - const uint64_t b = Utils::loadMachineEndian< uint64_t >(reinterpret_cast(ip.as.sa_in6.sin6_addr.s6_addr) + 8); - const uint16_t p = ip.as.sa_in6.sin6_port; - m_hashCode = Utils::hash64(a ^ b ^ ((uint64_t)p) ^ Utils::s_mapNonce); - m_ipv6Net64 = a; // IPv6 /64 - m_port = p; - } else { - // This is not reachable since InetAddress can only be AF_INET or AF_INET6, but implement something. - m_hashCode = Utils::fnv1a32(&ip, sizeof(InetAddress)); - m_ipv6Net64 = 0; - m_port = (uint16_t)family; - } - } - } + ZT_INLINE Key(const InetAddress& ip) noexcept + { + const unsigned int family = ip.as.sa.sa_family; + if (family == AF_INET) { + const uint16_t p = (uint16_t)ip.as.sa_in.sin_port; + m_hashCode = + Utils::hash64((((uint64_t)ip.as.sa_in.sin_addr.s_addr) << 16U) ^ ((uint64_t)p) ^ Utils::s_mapNonce); + m_ipv6Net64 = 0; // 0 for IPv4, never 0 for IPv6 + m_port = p; + } + else { + if (likely(family == AF_INET6)) { + const uint64_t a = Utils::loadMachineEndian( + reinterpret_cast(ip.as.sa_in6.sin6_addr.s6_addr)); + const uint64_t b = Utils::loadMachineEndian( + reinterpret_cast(ip.as.sa_in6.sin6_addr.s6_addr) + 8); + const uint16_t p = ip.as.sa_in6.sin6_port; + m_hashCode = Utils::hash64(a ^ b ^ ((uint64_t)p) ^ Utils::s_mapNonce); + m_ipv6Net64 = a; // IPv6 /64 + m_port = p; + } + else { + // This is not reachable since InetAddress can only be AF_INET or AF_INET6, but implement something. + m_hashCode = Utils::fnv1a32(&ip, sizeof(InetAddress)); + m_ipv6Net64 = 0; + m_port = (uint16_t)family; + } + } + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)m_hashCode; } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)m_hashCode; + } - ZT_INLINE bool operator==(const Key &k) const noexcept - { return (m_hashCode == k.m_hashCode) && (m_ipv6Net64 == k.m_ipv6Net64) && (m_port == k.m_port); } + ZT_INLINE bool operator==(const Key& k) const noexcept + { + return (m_hashCode == k.m_hashCode) && (m_ipv6Net64 == k.m_ipv6Net64) && (m_port == k.m_port); + } - ZT_INLINE bool operator!=(const Key &k) const noexcept - { return (!(*this == k)); } + ZT_INLINE bool operator!=(const Key& k) const noexcept + { + return (! (*this == k)); + } - ZT_INLINE bool operator<(const Key &k) const noexcept - { - if (m_hashCode < k.m_hashCode) { - return true; - } else if (m_hashCode == k.m_hashCode) { - if (m_ipv6Net64 < k.m_ipv6Net64) { - return true; - } else if (m_ipv6Net64 == k.m_ipv6Net64) { - return (m_port < k.m_port); - } - } - return false; - } + ZT_INLINE bool operator<(const Key& k) const noexcept + { + if (m_hashCode < k.m_hashCode) { + return true; + } + else if (m_hashCode == k.m_hashCode) { + if (m_ipv6Net64 < k.m_ipv6Net64) { + return true; + } + else if (m_ipv6Net64 == k.m_ipv6Net64) { + return (m_port < k.m_port); + } + } + return false; + } - ZT_INLINE bool operator>(const Key &k) const noexcept - { return (k < *this); } + ZT_INLINE bool operator>(const Key& k) const noexcept + { + return (k < *this); + } - ZT_INLINE bool operator<=(const Key &k) const noexcept - { return !(k < *this); } + ZT_INLINE bool operator<=(const Key& k) const noexcept + { + return ! (k < *this); + } - ZT_INLINE bool operator>=(const Key &k) const noexcept - { return !(*this < k); } + ZT_INLINE bool operator>=(const Key& k) const noexcept + { + return ! (*this < k); + } - private: - uint64_t m_hashCode; - uint64_t m_ipv6Net64; - uint16_t m_port; - }; + private: + uint64_t m_hashCode; + uint64_t m_ipv6Net64; + uint16_t m_port; + }; - ZT_INLINE Path(const int64_t l, const InetAddress &r) noexcept: - m_localSocket(l), - m_lastIn(0), - m_lastOut(0), - m_latency(-1), - m_addr(r) - {} + ZT_INLINE Path(const int64_t l, const InetAddress& r) noexcept + : m_localSocket(l) + , m_lastIn(0) + , m_lastOut(0) + , m_latency(-1) + , m_addr(r) + { + } - /** - * Send a packet via this path (last out time is also updated) - * - * @param data Packet data - * @param len Packet length - * @return True if transport reported success - */ - bool send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept; + /** + * Send a packet via this path (last out time is also updated) + * + * @param data Packet data + * @param len Packet length + * @return True if transport reported success + */ + bool send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept; - /** - * Explicitly update last sent time - * - * @param now Time of send - * @param bytes Bytes sent - */ - ZT_INLINE void sent(const CallContext &cc, const unsigned int bytes) noexcept - { - m_lastOut.store(cc.ticks, std::memory_order_relaxed); - m_outMeter.log(cc.ticks, bytes); - } + /** + * Explicitly update last sent time + * + * @param now Time of send + * @param bytes Bytes sent + */ + ZT_INLINE void sent(const CallContext& cc, const unsigned int bytes) noexcept + { + m_lastOut.store(cc.ticks, std::memory_order_relaxed); + m_outMeter.log(cc.ticks, bytes); + } - /** - * Called when a packet is received from this remote path, regardless of content - * - * @param now Time of receive - * @param bytes Bytes received - */ - ZT_INLINE void received(const CallContext &cc, const unsigned int bytes) noexcept - { - m_lastIn.store(cc.ticks, std::memory_order_relaxed); - m_inMeter.log(cc.ticks, bytes); - } + /** + * Called when a packet is received from this remote path, regardless of content + * + * @param now Time of receive + * @param bytes Bytes received + */ + ZT_INLINE void received(const CallContext& cc, const unsigned int bytes) noexcept + { + m_lastIn.store(cc.ticks, std::memory_order_relaxed); + m_inMeter.log(cc.ticks, bytes); + } - /** - * Update latency with a new measurement - * - * @param newMeasurement New latency measurement in milliseconds - */ - ZT_INLINE void updateLatency(const unsigned int newMeasurement) noexcept - { - const int lat = m_latency.load(std::memory_order_relaxed); - if (likely(lat > 0)) { - m_latency.store((lat + (int)newMeasurement) >> 1U, std::memory_order_relaxed); - } else { - m_latency.store((int)newMeasurement, std::memory_order_relaxed); - } - } + /** + * Update latency with a new measurement + * + * @param newMeasurement New latency measurement in milliseconds + */ + ZT_INLINE void updateLatency(const unsigned int newMeasurement) noexcept + { + const int lat = m_latency.load(std::memory_order_relaxed); + if (likely(lat > 0)) { + m_latency.store((lat + (int)newMeasurement) >> 1U, std::memory_order_relaxed); + } + else { + m_latency.store((int)newMeasurement, std::memory_order_relaxed); + } + } - /** - * @return Latency in milliseconds or -1 if unknown - */ - ZT_INLINE int latency() const noexcept - { return m_latency.load(std::memory_order_relaxed); } + /** + * @return Latency in milliseconds or -1 if unknown + */ + ZT_INLINE int latency() const noexcept + { + return m_latency.load(std::memory_order_relaxed); + } - /** - * Check path aliveness - * - * @param now Current time - */ - ZT_INLINE bool alive(const CallContext &cc) const noexcept - { return ((cc.ticks - m_lastIn.load(std::memory_order_relaxed)) < ZT_PATH_ALIVE_TIMEOUT); } + /** + * Check path aliveness + * + * @param now Current time + */ + ZT_INLINE bool alive(const CallContext& cc) const noexcept + { + return ((cc.ticks - m_lastIn.load(std::memory_order_relaxed)) < ZT_PATH_ALIVE_TIMEOUT); + } - /** - * @return Physical address - */ - ZT_INLINE const InetAddress &address() const noexcept - { return m_addr; } + /** + * @return Physical address + */ + ZT_INLINE const InetAddress& address() const noexcept + { + return m_addr; + } - /** - * @return Local socket as specified by external code - */ - ZT_INLINE int64_t localSocket() const noexcept - { return m_localSocket; } + /** + * @return Local socket as specified by external code + */ + ZT_INLINE int64_t localSocket() const noexcept + { + return m_localSocket; + } - /** - * @return Last time we received anything - */ - ZT_INLINE int64_t lastIn() const noexcept - { return m_lastIn.load(std::memory_order_relaxed); } + /** + * @return Last time we received anything + */ + ZT_INLINE int64_t lastIn() const noexcept + { + return m_lastIn.load(std::memory_order_relaxed); + } - /** - * @return Last time we sent something - */ - ZT_INLINE int64_t lastOut() const noexcept - { return m_lastOut.load(std::memory_order_relaxed); } + /** + * @return Last time we sent something + */ + ZT_INLINE int64_t lastOut() const noexcept + { + return m_lastOut.load(std::memory_order_relaxed); + } -private: - const int64_t m_localSocket; - std::atomic< int64_t > m_lastIn; - std::atomic< int64_t > m_lastOut; - std::atomic< int > m_latency; - const InetAddress m_addr; - Meter<> m_inMeter; - Meter<> m_outMeter; + private: + const int64_t m_localSocket; + std::atomic m_lastIn; + std::atomic m_lastOut; + std::atomic m_latency; + const InetAddress m_addr; + Meter<> m_inMeter; + Meter<> m_outMeter; - // These fields belong to Defragmenter but are kept in Path for performance - // as it's much faster this way than having Defragmenter maintain another - // mapping from paths to inbound message IDs. - Set< uint64_t > m_inboundFragmentedMessages; - Mutex m_inboundFragmentedMessages_l; + // These fields belong to Defragmenter but are kept in Path for performance + // as it's much faster this way than having Defragmenter maintain another + // mapping from paths to inbound message IDs. + Set m_inboundFragmentedMessages; + Mutex m_inboundFragmentedMessages_l; - std::atomic< int > __refCount; + std::atomic __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Peer.cpp b/core/Peer.cpp index dc8042ff1..eb93260d5 100644 --- a/core/Peer.cpp +++ b/core/Peer.cpp @@ -11,709 +11,819 @@ */ /****/ +#include "Peer.hpp" + #include "Constants.hpp" #include "Context.hpp" -#include "Trace.hpp" -#include "Peer.hpp" -#include "Topology.hpp" -#include "SelfAwareness.hpp" -#include "InetAddress.hpp" -#include "Protocol.hpp" #include "Endpoint.hpp" #include "Expect.hpp" +#include "InetAddress.hpp" +#include "Protocol.hpp" +#include "SelfAwareness.hpp" +#include "Topology.hpp" +#include "Trace.hpp" namespace ZeroTier { // An arbitrary byte to send in single byte probes, incremented on each probe. static uint8_t s_arbitraryByte = (uint8_t)Utils::random(); -Peer::Peer() : - m_key((uintptr_t)&m_identityKey), - m_keyRenegotiationNeeded(false), - m_lastReceive(0), - m_lastSend(0), - m_lastSentHello(0), - m_lastWhoisRequestReceived(0), - m_lastEchoRequestReceived(0), - m_lastProbeReceived(0), - m_alivePathCount(0), - m_bestPath(0), - m_vProto(0), - m_vMajor(0), - m_vMinor(0), - m_vRevision(0) -{} +Peer::Peer() + : m_key((uintptr_t)&m_identityKey) + , m_keyRenegotiationNeeded(false) + , m_lastReceive(0) + , m_lastSend(0) + , m_lastSentHello(0) + , m_lastWhoisRequestReceived(0) + , m_lastEchoRequestReceived(0) + , m_lastProbeReceived(0) + , m_alivePathCount(0) + , m_bestPath(0) + , m_vProto(0) + , m_vMajor(0) + , m_vMinor(0) + , m_vRevision(0) +{ +} Peer::~Peer() -{ Utils::burn(m_helloMacKey, sizeof(m_helloMacKey)); } - -bool Peer::init(const Context &ctx, const CallContext &cc, const Identity &peerIdentity) { - RWMutex::Lock l(m_lock); + Utils::burn(m_helloMacKey, sizeof(m_helloMacKey)); +} - m_id = peerIdentity; +bool Peer::init(const Context& ctx, const CallContext& cc, const Identity& peerIdentity) +{ + RWMutex::Lock l(m_lock); - uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; - if (unlikely(!ctx.identity.agree(peerIdentity, k))) - return false; - m_identityKey.init(cc.ticks, k); - Utils::burn(k, sizeof(k)); + m_id = peerIdentity; - m_deriveSecondaryIdentityKeys(); + uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; + if (unlikely(! ctx.identity.agree(peerIdentity, k))) + return false; + m_identityKey.init(cc.ticks, k); + Utils::burn(k, sizeof(k)); - return true; + m_deriveSecondaryIdentityKeys(); + + return true; } void Peer::received( - const Context &ctx, - const CallContext &cc, - const SharedPtr< Path > &path, - const unsigned int hops, - const uint64_t packetId, - const unsigned int payloadLength, - const Protocol::Verb verb, - const Protocol::Verb /*inReVerb*/) + const Context& ctx, + const CallContext& cc, + const SharedPtr& path, + const unsigned int hops, + const uint64_t packetId, + const unsigned int payloadLength, + const Protocol::Verb verb, + const Protocol::Verb /*inReVerb*/) { - m_lastReceive.store(cc.ticks, std::memory_order_relaxed); - m_inMeter.log(cc.ticks, payloadLength); + m_lastReceive.store(cc.ticks, std::memory_order_relaxed); + m_inMeter.log(cc.ticks, payloadLength); - // NOTE: in the most common scenario we will be talking via the best path. - // This does a check without a full mutex lock and if so there's nothing more - // to do, which speeds things up in that case. - if ((hops == 0) && ((uintptr_t)path.ptr() != m_bestPath.load(std::memory_order_relaxed))) { - RWMutex::RMaybeWLock l(m_lock); + // NOTE: in the most common scenario we will be talking via the best path. + // This does a check without a full mutex lock and if so there's nothing more + // to do, which speeds things up in that case. + if ((hops == 0) && ((uintptr_t)path.ptr() != m_bestPath.load(std::memory_order_relaxed))) { + RWMutex::RMaybeWLock l(m_lock); - // If this matches an existing path, skip path learning stuff. For the small number - // of paths a peer will have linear scan is the fastest way to do lookup. - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if (m_paths[i] == path) - return; - } + // If this matches an existing path, skip path learning stuff. For the small number + // of paths a peer will have linear scan is the fastest way to do lookup. + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if (m_paths[i] == path) + return; + } - // If we made it here, we don't already know this path. - if (ctx.node->filterPotentialPath(cc.tPtr, m_id, path->localSocket(), path->address())) { - // SECURITY: note that if we've made it here we expected this OK, see Expect.hpp. - // There is replay protection in effect for OK responses. - if (verb == Protocol::VERB_OK) { - // Acquire write access to the object and thus path set. - l.writing(); + // If we made it here, we don't already know this path. + if (ctx.node->filterPotentialPath(cc.tPtr, m_id, path->localSocket(), path->address())) { + // SECURITY: note that if we've made it here we expected this OK, see Expect.hpp. + // There is replay protection in effect for OK responses. + if (verb == Protocol::VERB_OK) { + // Acquire write access to the object and thus path set. + l.writing(); - unsigned int newPathIdx; - if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) { - m_prioritizePaths(cc); - if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) { - newPathIdx = ZT_MAX_PEER_NETWORK_PATHS - 1; - } else { - newPathIdx = m_alivePathCount++; - } - } else { - newPathIdx = m_alivePathCount++; - } + unsigned int newPathIdx; + if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) { + m_prioritizePaths(cc); + if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) { + newPathIdx = ZT_MAX_PEER_NETWORK_PATHS - 1; + } + else { + newPathIdx = m_alivePathCount++; + } + } + else { + newPathIdx = m_alivePathCount++; + } - // Save a reference to the current path in case we replace it. This - // should technically never happen, but this ensures safety if it does. - const SharedPtr< Path > currentBest(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); + // Save a reference to the current path in case we replace it. This + // should technically never happen, but this ensures safety if it does. + const SharedPtr currentBest(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); - SharedPtr< Path > old; - old.move(m_paths[newPathIdx]); - m_paths[newPathIdx] = path; + SharedPtr old; + old.move(m_paths[newPathIdx]); + m_paths[newPathIdx] = path; - m_prioritizePaths(cc); + m_prioritizePaths(cc); - ctx.t->learnedNewPath(cc, 0x582fabdd, packetId, m_id, path->address(), (old) ? old->address() : InetAddress()); - } else { - int64_t < = m_lastTried[Endpoint(path->address())]; - if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) { - lt = cc.ticks; - path->sent(cc, m_hello(ctx, cc, path->localSocket(), path->address(), false)); - ctx.t->tryingNewPath(cc, 0xb7747ddd, m_id, path->address(), path->address(), packetId, (uint8_t)verb, m_id); - } - } - } - } + ctx.t->learnedNewPath( + cc, + 0x582fabdd, + packetId, + m_id, + path->address(), + (old) ? old->address() : InetAddress()); + } + else { + int64_t& lt = m_lastTried[Endpoint(path->address())]; + if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) { + lt = cc.ticks; + path->sent(cc, m_hello(ctx, cc, path->localSocket(), path->address(), false)); + ctx.t->tryingNewPath( + cc, + 0xb7747ddd, + m_id, + path->address(), + path->address(), + packetId, + (uint8_t)verb, + m_id); + } + } + } + } } -void Peer::send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept +void Peer::send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept { - SharedPtr< Path > via(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); - if (likely(via)) { - if (likely(via->send(ctx, cc, data, len))) - this->sent(cc, len); - } else { - const SharedPtr< Peer > root(ctx.topology->root()); - if (likely((root) && (root.ptr() != this))) { - via = root->path(cc); - if (likely(via)) { - if (likely(via->send(ctx, cc, data, len))) { - root->relayed(cc, len); - this->sent(cc, len); - } - } - } - } + SharedPtr via(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); + if (likely(via)) { + if (likely(via->send(ctx, cc, data, len))) + this->sent(cc, len); + } + else { + const SharedPtr root(ctx.topology->root()); + if (likely((root) && (root.ptr() != this))) { + via = root->path(cc); + if (likely(via)) { + if (likely(via->send(ctx, cc, data, len))) { + root->relayed(cc, len); + this->sent(cc, len); + } + } + } + } } -void Peer::pulse(const Context &ctx, const CallContext &cc) +void Peer::pulse(const Context& ctx, const CallContext& cc) { - RWMutex::Lock l(m_lock); + RWMutex::Lock l(m_lock); - // Grab current key (this is never NULL). - SymmetricKey *const key = reinterpret_cast(m_key.load(std::memory_order_relaxed)); + // Grab current key (this is never NULL). + SymmetricKey* const key = reinterpret_cast(m_key.load(std::memory_order_relaxed)); - // Determine if we need a new ephemeral key pair and if a new HELLO needs - // to be sent. The latter happens every ZT_PEER_HELLO_INTERVAL or if a new - // ephemeral key pair is generated. - bool needHello = (((m_vProto >= 20) && (m_keyRenegotiationNeeded || (key == &m_identityKey) || ((cc.ticks - key->timestamp()) >= (ZT_SYMMETRIC_KEY_TTL / 2)) || (key->odometer() > (ZT_SYMMETRIC_KEY_TTL_MESSAGES / 2)))) || ((cc.ticks - m_lastSentHello) >= ZT_PEER_HELLO_INTERVAL)); + // Determine if we need a new ephemeral key pair and if a new HELLO needs + // to be sent. The latter happens every ZT_PEER_HELLO_INTERVAL or if a new + // ephemeral key pair is generated. + bool needHello = + (((m_vProto >= 20) + && (m_keyRenegotiationNeeded || (key == &m_identityKey) + || ((cc.ticks - key->timestamp()) >= (ZT_SYMMETRIC_KEY_TTL / 2)) + || (key->odometer() > (ZT_SYMMETRIC_KEY_TTL_MESSAGES / 2)))) + || ((cc.ticks - m_lastSentHello) >= ZT_PEER_HELLO_INTERVAL)); - // Prioritize paths and more importantly for here forget dead ones. - m_prioritizePaths(cc); + // Prioritize paths and more importantly for here forget dead ones. + m_prioritizePaths(cc); - if (m_tryQueue.empty()) { - if (m_alivePathCount == 0) { - // If there are no living paths and nothing in the try queue, try addresses - // from any locator we have on file or that are fetched via the external API - // callback (if one was supplied). + if (m_tryQueue.empty()) { + if (m_alivePathCount == 0) { + // If there are no living paths and nothing in the try queue, try addresses + // from any locator we have on file or that are fetched via the external API + // callback (if one was supplied). - if (m_locator) { - for (Vector< std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > >::const_iterator ep(m_locator->endpoints().begin()); ep != m_locator->endpoints().end(); ++ep) { - if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) { - if (ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, ep->first.ip())) { - int64_t < = m_lastTried[ep->first]; - if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { - lt = cc.ticks; - ctx.t->tryingNewPath(cc, 0x84b22322, m_id, ep->first.ip(), InetAddress::NIL, 0, 0, Identity::NIL); - sent(cc, m_sendProbe(ctx, cc, -1, ep->first.ip(), nullptr, 0)); - } - } - } - } - } + if (m_locator) { + for (Vector > >::const_iterator ep( + m_locator->endpoints().begin()); + ep != m_locator->endpoints().end(); + ++ep) { + if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) { + if (ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, ep->first.ip())) { + int64_t& lt = m_lastTried[ep->first]; + if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { + lt = cc.ticks; + ctx.t->tryingNewPath( + cc, + 0x84b22322, + m_id, + ep->first.ip(), + InetAddress::NIL, + 0, + 0, + Identity::NIL); + sent(cc, m_sendProbe(ctx, cc, -1, ep->first.ip(), nullptr, 0)); + } + } + } + } + } - InetAddress addr; - if (ctx.node->externalPathLookup(cc.tPtr, m_id, -1, addr)) { - if ((addr) && ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, addr)) { - int64_t < = m_lastTried[Endpoint(addr)]; - if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { - lt = cc.ticks; - ctx.t->tryingNewPath(cc, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL); - sent(cc, m_sendProbe(ctx, cc, -1, addr, nullptr, 0)); - } - } - } - } - } else { - unsigned int attempts = 0; - for (;;) { - p_TryQueueItem &qi = m_tryQueue.front(); + InetAddress addr; + if (ctx.node->externalPathLookup(cc.tPtr, m_id, -1, addr)) { + if ((addr) && ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, addr)) { + int64_t& lt = m_lastTried[Endpoint(addr)]; + if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { + lt = cc.ticks; + ctx.t->tryingNewPath(cc, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL); + sent(cc, m_sendProbe(ctx, cc, -1, addr, nullptr, 0)); + } + } + } + } + } + else { + unsigned int attempts = 0; + for (;;) { + p_TryQueueItem& qi = m_tryQueue.front(); - if (qi.target.isInetAddr()) { - // Skip entry if it overlaps with any currently active IP. - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if (m_paths[i]->address().ipsEqual(qi.target.ip())) - goto discard_queue_item; - } - } + if (qi.target.isInetAddr()) { + // Skip entry if it overlaps with any currently active IP. + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if (m_paths[i]->address().ipsEqual(qi.target.ip())) + goto discard_queue_item; + } + } - if (qi.target.type == ZT_ENDPOINT_TYPE_IP_UDP) { - // TODO: need to send something like a NOP for older target nodes. + if (qi.target.type == ZT_ENDPOINT_TYPE_IP_UDP) { + // TODO: need to send something like a NOP for older target nodes. - ++attempts; - if (qi.iteration < 0) { + ++attempts; + if (qi.iteration < 0) { + // If iteration is less than zero, try to contact the original address. + // It may be set to a larger negative value to try multiple times such + // as e.g. -3 to try 3 times. + sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), nullptr, 0)); + ++qi.iteration; + goto requeue_item; + } + else if (qi.target.ip().isV4() && (m_alivePathCount == 0)) { + // When iteration reaches zero the queue item is dropped unless it's + // IPv4 and we have no direct paths. In that case some heavier NAT-t + // strategies are attempted. - // If iteration is less than zero, try to contact the original address. - // It may be set to a larger negative value to try multiple times such - // as e.g. -3 to try 3 times. - sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), nullptr, 0)); - ++qi.iteration; - goto requeue_item; + if (qi.target.ip().port() < 1024) { + // If the source port is privileged, we actually scan every possible + // privileged port in random order slowly over multiple iterations + // of pulse(). This is done in batches of ZT_NAT_T_PORT_SCAN_MAX. + uint16_t ports[ZT_NAT_T_PORT_SCAN_MAX]; + unsigned int pn = 0; + while ((pn < ZT_NAT_T_PORT_SCAN_MAX) && (qi.iteration < 1023)) { + const uint16_t p = ctx.randomPrivilegedPortOrder[qi.iteration++]; + if ((unsigned int)p != qi.target.ip().port()) + ports[pn++] = p; + } + if (pn > 0) + sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), ports, pn)); + if (qi.iteration < 1023) + goto requeue_item; + } + else { + // For un-privileged ports we'll try ZT_NAT_T_PORT_SCAN_MAX ports + // beyond the one we were sent to catch some sequentially assigning + // symmetric NATs. + InetAddress tmp(qi.target.ip()); + unsigned int p = tmp.port() + 1 + (unsigned int)qi.iteration++; + if (p > 65535) + p -= 64512; // wrap back to 1024 + tmp.setPort(p); + sent(cc, m_sendProbe(ctx, cc, -1, tmp, nullptr, 0)); + if (qi.iteration < ZT_NAT_T_PORT_SCAN_MAX) + goto requeue_item; + } + } + } - } else if (qi.target.ip().isV4() && (m_alivePathCount == 0)) { - // When iteration reaches zero the queue item is dropped unless it's - // IPv4 and we have no direct paths. In that case some heavier NAT-t - // strategies are attempted. + // Discard front item unless the code skips to requeue_item. + discard_queue_item: + m_tryQueue.pop_front(); + if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) + break; + else + continue; - if (qi.target.ip().port() < 1024) { + // If the code skips here the front item is instead moved to the back. + requeue_item: + if (m_tryQueue.size() > 1) // no point in doing this splice if there's only one item + m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin()); + if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) + break; + else + continue; + } + } - // If the source port is privileged, we actually scan every possible - // privileged port in random order slowly over multiple iterations - // of pulse(). This is done in batches of ZT_NAT_T_PORT_SCAN_MAX. - uint16_t ports[ZT_NAT_T_PORT_SCAN_MAX]; - unsigned int pn = 0; - while ((pn < ZT_NAT_T_PORT_SCAN_MAX) && (qi.iteration < 1023)) { - const uint16_t p = ctx.randomPrivilegedPortOrder[qi.iteration++]; - if ((unsigned int)p != qi.target.ip().port()) - ports[pn++] = p; - } - if (pn > 0) - sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), ports, pn)); - if (qi.iteration < 1023) - goto requeue_item; + // Do keepalive on all currently active paths, sending HELLO to the first + // if needHello is true and sending small keepalives to others. + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if (needHello) { + needHello = false; + const unsigned int bytes = + m_hello(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), m_keyRenegotiationNeeded); + if (bytes) { + m_paths[i]->sent(cc, bytes); + sent(cc, bytes); + m_lastSentHello = cc.ticks; + m_keyRenegotiationNeeded = false; + } + } + else if ((cc.ticks - m_paths[i]->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) { + m_paths[i]->send(ctx, cc, &s_arbitraryByte, 1); + ++s_arbitraryByte; + sent(cc, 1); + } + } - } else { + // Send a HELLO indirectly if we were not able to send one via any direct path. + if (needHello) { + const SharedPtr root(ctx.topology->root()); + if (root) { + const SharedPtr via(root->path(cc)); + if (via) { + const unsigned int bytes = + m_hello(ctx, cc, via->localSocket(), via->address(), m_keyRenegotiationNeeded); + if (bytes) { + via->sent(cc, bytes); + root->relayed(cc, bytes); + sent(cc, bytes); + m_lastSentHello = cc.ticks; + m_keyRenegotiationNeeded = false; + } + } + } + } - // For un-privileged ports we'll try ZT_NAT_T_PORT_SCAN_MAX ports - // beyond the one we were sent to catch some sequentially assigning - // symmetric NATs. - InetAddress tmp(qi.target.ip()); - unsigned int p = tmp.port() + 1 + (unsigned int)qi.iteration++; - if (p > 65535) - p -= 64512; // wrap back to 1024 - tmp.setPort(p); - sent(cc, m_sendProbe(ctx, cc, -1, tmp, nullptr, 0)); - if (qi.iteration < ZT_NAT_T_PORT_SCAN_MAX) - goto requeue_item; - - } - } - } - - // Discard front item unless the code skips to requeue_item. - discard_queue_item: - m_tryQueue.pop_front(); - if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) - break; - else continue; - - // If the code skips here the front item is instead moved to the back. - requeue_item: - if (m_tryQueue.size() > 1) // no point in doing this splice if there's only one item - m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin()); - if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) - break; - else continue; - } - } - - // Do keepalive on all currently active paths, sending HELLO to the first - // if needHello is true and sending small keepalives to others. - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if (needHello) { - needHello = false; - const unsigned int bytes = m_hello(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), m_keyRenegotiationNeeded); - if (bytes) { - m_paths[i]->sent(cc, bytes); - sent(cc, bytes); - m_lastSentHello = cc.ticks; - m_keyRenegotiationNeeded = false; - } - } else if ((cc.ticks - m_paths[i]->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) { - m_paths[i]->send(ctx, cc, &s_arbitraryByte, 1); - ++s_arbitraryByte; - sent(cc, 1); - } - } - - // Send a HELLO indirectly if we were not able to send one via any direct path. - if (needHello) { - const SharedPtr< Peer > root(ctx.topology->root()); - if (root) { - const SharedPtr< Path > via(root->path(cc)); - if (via) { - const unsigned int bytes = m_hello(ctx, cc, via->localSocket(), via->address(), m_keyRenegotiationNeeded); - if (bytes) { - via->sent(cc, bytes); - root->relayed(cc, bytes); - sent(cc, bytes); - m_lastSentHello = cc.ticks; - m_keyRenegotiationNeeded = false; - } - } - } - } - - // Clean m_lastTried - for (Map< Endpoint, int64_t >::iterator i(m_lastTried.begin()); i != m_lastTried.end();) { - if ((cc.ticks - i->second) > (ZT_PATH_MIN_TRY_INTERVAL * 3)) - m_lastTried.erase(i++); - else ++i; - } + // Clean m_lastTried + for (Map::iterator i(m_lastTried.begin()); i != m_lastTried.end();) { + if ((cc.ticks - i->second) > (ZT_PATH_MIN_TRY_INTERVAL * 3)) + m_lastTried.erase(i++); + else + ++i; + } } -void Peer::contact(const Context &ctx, const CallContext &cc, const Endpoint &ep, int tries) +void Peer::contact(const Context& ctx, const CallContext& cc, const Endpoint& ep, int tries) { - RWMutex::Lock l(m_lock); + RWMutex::Lock l(m_lock); - // See if there's already a path to this endpoint and if so ignore it. - if (ep.isInetAddr()) { - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if (m_paths[i]->address().ipsEqual(ep.ip())) - return; - } - } + // See if there's already a path to this endpoint and if so ignore it. + if (ep.isInetAddr()) { + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if (m_paths[i]->address().ipsEqual(ep.ip())) + return; + } + } - // Check underlying path attempt rate limit. - int64_t < = m_lastTried[ep]; - if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) - return; - lt = cc.ticks; + // Check underlying path attempt rate limit. + int64_t& lt = m_lastTried[ep]; + if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) + return; + lt = cc.ticks; - // For IPv4 addresses we send a tiny packet with a low TTL, which helps to - // traverse some NAT types. It has no effect otherwise. - if (ep.isInetAddr() && ep.ip().isV4()) { - ctx.cb.wirePacketSendFunction(reinterpret_cast(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast(&ep.ip()), &s_arbitraryByte, 1, 2); - ++s_arbitraryByte; - } + // For IPv4 addresses we send a tiny packet with a low TTL, which helps to + // traverse some NAT types. It has no effect otherwise. + if (ep.isInetAddr() && ep.ip().isV4()) { + ctx.cb.wirePacketSendFunction( + reinterpret_cast(ctx.node), + ctx.uPtr, + cc.tPtr, + -1, + reinterpret_cast(&ep.ip()), + &s_arbitraryByte, + 1, + 2); + ++s_arbitraryByte; + } - // Make sure address is not already in the try queue. If so just update it. - for (List< p_TryQueueItem >::iterator i(m_tryQueue.begin()); i != m_tryQueue.end(); ++i) { - if (i->target.isSameAddress(ep)) { - i->target = ep; - i->iteration = -tries; - return; - } - } + // Make sure address is not already in the try queue. If so just update it. + for (List::iterator i(m_tryQueue.begin()); i != m_tryQueue.end(); ++i) { + if (i->target.isSameAddress(ep)) { + i->target = ep; + i->iteration = -tries; + return; + } + } - m_tryQueue.push_back(p_TryQueueItem(ep, -tries)); + m_tryQueue.push_back(p_TryQueueItem(ep, -tries)); } -void Peer::resetWithinScope(const Context &ctx, const CallContext &cc, InetAddress::IpScope scope, int inetAddressFamily) +void Peer::resetWithinScope( + const Context& ctx, + const CallContext& cc, + InetAddress::IpScope scope, + int inetAddressFamily) { - RWMutex::Lock l(m_lock); - unsigned int pc = 0; - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if ((m_paths[i]) && (((int)m_paths[i]->address().as.sa.sa_family == inetAddressFamily) && (m_paths[i]->address().ipScope() == scope))) { - const unsigned int bytes = m_sendProbe(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), nullptr, 0); - m_paths[i]->sent(cc, bytes); - sent(cc, bytes); - } else if (pc != i) { - m_paths[pc++] = m_paths[i]; - } - } - m_alivePathCount = pc; - while (pc < ZT_MAX_PEER_NETWORK_PATHS) - m_paths[pc++].zero(); + RWMutex::Lock l(m_lock); + unsigned int pc = 0; + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if ((m_paths[i]) + && (((int)m_paths[i]->address().as.sa.sa_family == inetAddressFamily) + && (m_paths[i]->address().ipScope() == scope))) { + const unsigned int bytes = + m_sendProbe(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), nullptr, 0); + m_paths[i]->sent(cc, bytes); + sent(cc, bytes); + } + else if (pc != i) { + m_paths[pc++] = m_paths[i]; + } + } + m_alivePathCount = pc; + while (pc < ZT_MAX_PEER_NETWORK_PATHS) + m_paths[pc++].zero(); } -void Peer::save(const Context &ctx, const CallContext &cc) const +void Peer::save(const Context& ctx, const CallContext& cc) const { - uint8_t buf[8 + ZT_PEER_MARSHAL_SIZE_MAX]; + uint8_t buf[8 + ZT_PEER_MARSHAL_SIZE_MAX]; - // Prefix each saved peer with the current timestamp. - Utils::storeBigEndian< uint64_t >(buf, (uint64_t)cc.clock); + // Prefix each saved peer with the current timestamp. + Utils::storeBigEndian(buf, (uint64_t)cc.clock); - const int len = marshal(ctx, buf + 8); - if (len > 0) { - uint64_t id[2]; - id[0] = m_id.address().toInt(); - id[1] = 0; - ctx.store->put(cc, ZT_STATE_OBJECT_PEER, id, 1, buf, (unsigned int)len + 8); - } + const int len = marshal(ctx, buf + 8); + if (len > 0) { + uint64_t id[2]; + id[0] = m_id.address().toInt(); + id[1] = 0; + ctx.store->put(cc, ZT_STATE_OBJECT_PEER, id, 1, buf, (unsigned int)len + 8); + } } -int Peer::marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept +int Peer::marshal(const Context& ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept { - RWMutex::RLock l(m_lock); + RWMutex::RLock l(m_lock); - data[0] = 16; // serialized peer version + data[0] = 16; // serialized peer version - // Include our identity's address to detect if this changes and require - // recomputation of m_identityKey. - ctx.identity.address().copyTo(data + 1); + // Include our identity's address to detect if this changes and require + // recomputation of m_identityKey. + ctx.identity.address().copyTo(data + 1); - // SECURITY: encryption in place is only to protect secrets if they are - // cached to local storage. It's not used over the wire. Dumb ECB is fine - // because secret keys are random and have no structure to reveal. - ctx.localSecretCipher.encrypt(m_identityKey.key(), data + 1 + ZT_ADDRESS_LENGTH); - ctx.localSecretCipher.encrypt(m_identityKey.key() + 16, data + 1 + ZT_ADDRESS_LENGTH + 16); - ctx.localSecretCipher.encrypt(m_identityKey.key() + 32, data + 1 + ZT_ADDRESS_LENGTH + 32); + // SECURITY: encryption in place is only to protect secrets if they are + // cached to local storage. It's not used over the wire. Dumb ECB is fine + // because secret keys are random and have no structure to reveal. + ctx.localSecretCipher.encrypt(m_identityKey.key(), data + 1 + ZT_ADDRESS_LENGTH); + ctx.localSecretCipher.encrypt(m_identityKey.key() + 16, data + 1 + ZT_ADDRESS_LENGTH + 16); + ctx.localSecretCipher.encrypt(m_identityKey.key() + 32, data + 1 + ZT_ADDRESS_LENGTH + 32); - int p = 1 + ZT_ADDRESS_LENGTH + 48; + int p = 1 + ZT_ADDRESS_LENGTH + 48; - int s = m_id.marshal(data + p, false); - if (s < 0) - return -1; - p += s; + int s = m_id.marshal(data + p, false); + if (s < 0) + return -1; + p += s; - if (m_locator) { - data[p++] = 1; - s = m_locator->marshal(data + p); - if (s <= 0) - return s; - p += s; - } else { - data[p++] = 0; - } + if (m_locator) { + data[p++] = 1; + s = m_locator->marshal(data + p); + if (s <= 0) + return s; + p += s; + } + else { + data[p++] = 0; + } - Utils::storeBigEndian(data + p, (uint16_t)m_vProto); - p += 2; - Utils::storeBigEndian(data + p, (uint16_t)m_vMajor); - p += 2; - Utils::storeBigEndian(data + p, (uint16_t)m_vMinor); - p += 2; - Utils::storeBigEndian(data + p, (uint16_t)m_vRevision); - p += 2; + Utils::storeBigEndian(data + p, (uint16_t)m_vProto); + p += 2; + Utils::storeBigEndian(data + p, (uint16_t)m_vMajor); + p += 2; + Utils::storeBigEndian(data + p, (uint16_t)m_vMinor); + p += 2; + Utils::storeBigEndian(data + p, (uint16_t)m_vRevision); + p += 2; - data[p++] = 0; - data[p++] = 0; + data[p++] = 0; + data[p++] = 0; - return p; + return p; } -int Peer::unmarshal(const Context &ctx, const int64_t ticks, const uint8_t *restrict data, const int len) noexcept +int Peer::unmarshal(const Context& ctx, const int64_t ticks, const uint8_t* restrict data, const int len) noexcept { - RWMutex::Lock l(m_lock); + RWMutex::Lock l(m_lock); - if ((len <= (1 + ZT_ADDRESS_LENGTH + 48)) || (data[0] != 16)) - return -1; + if ((len <= (1 + ZT_ADDRESS_LENGTH + 48)) || (data[0] != 16)) + return -1; - for (unsigned int i = 0; i < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++i) { - m_ephemeralKeysSent[i].creationTime = -1; - m_ephemeralSessions[i].established = false; - } - m_key.store((uintptr_t)&m_identityKey, std::memory_order_relaxed); + for (unsigned int i = 0; i < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++i) { + m_ephemeralKeysSent[i].creationTime = -1; + m_ephemeralSessions[i].established = false; + } + m_key.store((uintptr_t)&m_identityKey, std::memory_order_relaxed); - bool identityKeyRestored = false; - if (Address(data + 1) == ctx.identity.address()) { - uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; - static_assert(ZT_SYMMETRIC_KEY_SIZE == 48, "marshal() and unmarshal() must be revisited if ZT_SYMMETRIC_KEY_SIZE is changed"); - ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH, k); - ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 16, k + 16); - ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 32, k + 32); - m_identityKey.init(ticks, k); - Utils::burn(k, sizeof(k)); - identityKeyRestored = true; - } + bool identityKeyRestored = false; + if (Address(data + 1) == ctx.identity.address()) { + uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; + static_assert( + ZT_SYMMETRIC_KEY_SIZE == 48, + "marshal() and unmarshal() must be revisited if ZT_SYMMETRIC_KEY_SIZE is changed"); + ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH, k); + ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 16, k + 16); + ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 32, k + 32); + m_identityKey.init(ticks, k); + Utils::burn(k, sizeof(k)); + identityKeyRestored = true; + } - int p = 1 + ZT_ADDRESS_LENGTH + 48; + int p = 1 + ZT_ADDRESS_LENGTH + 48; - int s = m_id.unmarshal(data + p, len - p); - if (s < 0) - return s; - p += s; + int s = m_id.unmarshal(data + p, len - p); + if (s < 0) + return s; + p += s; - if (!identityKeyRestored) { - uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; - if (!ctx.identity.agree(m_id, k)) - return -1; - m_identityKey.init(ticks, k); - Utils::burn(k, sizeof(k)); - } + if (! identityKeyRestored) { + uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; + if (! ctx.identity.agree(m_id, k)) + return -1; + m_identityKey.init(ticks, k); + Utils::burn(k, sizeof(k)); + } - if (p >= len) - return -1; - if (data[p] == 0) { - ++p; - m_locator.zero(); - } else if (data[p] == 1) { - ++p; - Locator *const loc = new Locator(); - s = loc->unmarshal(data + p, len - p); - m_locator.set(loc); - if (s < 0) - return s; - p += s; - } else { - return -1; - } + if (p >= len) + return -1; + if (data[p] == 0) { + ++p; + m_locator.zero(); + } + else if (data[p] == 1) { + ++p; + Locator* const loc = new Locator(); + s = loc->unmarshal(data + p, len - p); + m_locator.set(loc); + if (s < 0) + return s; + p += s; + } + else { + return -1; + } - if ((p + 10) > len) - return -1; - m_vProto = Utils::loadBigEndian< uint16_t >(data + p); - p += 2; - m_vMajor = Utils::loadBigEndian< uint16_t >(data + p); - p += 2; - m_vMinor = Utils::loadBigEndian< uint16_t >(data + p); - p += 2; - m_vRevision = Utils::loadBigEndian< uint16_t >(data + p); - p += 2; - p += 2 + (int)Utils::loadBigEndian< uint16_t >(data + p); + if ((p + 10) > len) + return -1; + m_vProto = Utils::loadBigEndian(data + p); + p += 2; + m_vMajor = Utils::loadBigEndian(data + p); + p += 2; + m_vMinor = Utils::loadBigEndian(data + p); + p += 2; + m_vRevision = Utils::loadBigEndian(data + p); + p += 2; + p += 2 + (int)Utils::loadBigEndian(data + p); - m_deriveSecondaryIdentityKeys(); + m_deriveSecondaryIdentityKeys(); - return (p > len) ? -1 : p; + return (p > len) ? -1 : p; } -struct _PathPriorityComparisonOperator -{ - ZT_INLINE bool operator()(const SharedPtr< Path > &a, const SharedPtr< Path > &b) const noexcept - { - if (a) { - if (b) - return (a->lastIn() > b->lastIn()); - else return true; - } else { - return false; - } - } +struct _PathPriorityComparisonOperator { + ZT_INLINE bool operator()(const SharedPtr& a, const SharedPtr& b) const noexcept + { + if (a) { + if (b) + return (a->lastIn() > b->lastIn()); + else + return true; + } + else { + return false; + } + } }; -void Peer::m_prioritizePaths(const CallContext &cc) +void Peer::m_prioritizePaths(const CallContext& cc) { - // assumes m_lock is locked + // assumes m_lock is locked - // Need to hold the current best just in case we drop it before changing the atomic. - const SharedPtr< Path > oldBest(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); + // Need to hold the current best just in case we drop it before changing the atomic. + const SharedPtr oldBest(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); - // Clean and reprioritize paths. - if (m_alivePathCount != 0) { - unsigned int newCnt = 0; - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - if ((m_paths[i]) && (m_paths[i]->alive(cc))) { - if (i != newCnt) - m_paths[newCnt].move(m_paths[i]); - ++newCnt; - } - } - for (unsigned int i = newCnt; i < m_alivePathCount; ++i) - m_paths[i].zero(); - m_alivePathCount = newCnt; + // Clean and reprioritize paths. + if (m_alivePathCount != 0) { + unsigned int newCnt = 0; + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + if ((m_paths[i]) && (m_paths[i]->alive(cc))) { + if (i != newCnt) + m_paths[newCnt].move(m_paths[i]); + ++newCnt; + } + } + for (unsigned int i = newCnt; i < m_alivePathCount; ++i) + m_paths[i].zero(); + m_alivePathCount = newCnt; - std::sort(m_paths, m_paths + newCnt, _PathPriorityComparisonOperator()); - } + std::sort(m_paths, m_paths + newCnt, _PathPriorityComparisonOperator()); + } - // Update atomic holding pointer to best path. - m_bestPath.store((m_alivePathCount != 0) ? (uintptr_t)m_paths[0].ptr() : (uintptr_t)0, std::memory_order_release); + // Update atomic holding pointer to best path. + m_bestPath.store((m_alivePathCount != 0) ? (uintptr_t)m_paths[0].ptr() : (uintptr_t)0, std::memory_order_release); } -unsigned int Peer::m_sendProbe(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const uint16_t *ports, const unsigned int numPorts) +unsigned int Peer::m_sendProbe( + const Context& ctx, + const CallContext& cc, + int64_t localSocket, + const InetAddress& atAddress, + const uint16_t* ports, + const unsigned int numPorts) { - // Assumes m_lock is locked + // Assumes m_lock is locked - // SECURITY: we use the long-lived identity key here since this is used for - // trial contacts, etc. It contains no meaningful payload so who cares if - // some future attacker compromises it. + // SECURITY: we use the long-lived identity key here since this is used for + // trial contacts, etc. It contains no meaningful payload so who cares if + // some future attacker compromises it. - uint8_t p[ZT_PROTO_MIN_PACKET_LENGTH]; - Utils::storeMachineEndian< uint64_t >(p + ZT_PROTO_PACKET_ID_INDEX, m_identityKey.nextMessage(ctx.identity.address(), m_id.address())); - m_id.address().copyTo(p + ZT_PROTO_PACKET_DESTINATION_INDEX); - ctx.identity.address().copyTo(p + ZT_PROTO_PACKET_SOURCE_INDEX); - p[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; - p[ZT_PROTO_PACKET_VERB_INDEX] = Protocol::VERB_NOP; + uint8_t p[ZT_PROTO_MIN_PACKET_LENGTH]; + Utils::storeMachineEndian( + p + ZT_PROTO_PACKET_ID_INDEX, + m_identityKey.nextMessage(ctx.identity.address(), m_id.address())); + m_id.address().copyTo(p + ZT_PROTO_PACKET_DESTINATION_INDEX); + ctx.identity.address().copyTo(p + ZT_PROTO_PACKET_SOURCE_INDEX); + p[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; + p[ZT_PROTO_PACKET_VERB_INDEX] = Protocol::VERB_NOP; - ctx.expect->sending(Protocol::armor(p, ZT_PROTO_MIN_PACKET_LENGTH, m_identityKey, cipher()), cc.ticks); + ctx.expect->sending(Protocol::armor(p, ZT_PROTO_MIN_PACKET_LENGTH, m_identityKey, cipher()), cc.ticks); - if (numPorts > 0) { - InetAddress tmp(atAddress); - for (unsigned int i = 0; i < numPorts; ++i) { - tmp.setPort(ports[i]); - ctx.cb.wirePacketSendFunction(reinterpret_cast(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast(&tmp), p, ZT_PROTO_MIN_PACKET_LENGTH, 0); - } - return ZT_PROTO_MIN_PACKET_LENGTH * numPorts; - } else { - ctx.cb.wirePacketSendFunction(reinterpret_cast(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast(&atAddress), p, ZT_PROTO_MIN_PACKET_LENGTH, 0); - return ZT_PROTO_MIN_PACKET_LENGTH; - } + if (numPorts > 0) { + InetAddress tmp(atAddress); + for (unsigned int i = 0; i < numPorts; ++i) { + tmp.setPort(ports[i]); + ctx.cb.wirePacketSendFunction( + reinterpret_cast(ctx.node), + ctx.uPtr, + cc.tPtr, + -1, + reinterpret_cast(&tmp), + p, + ZT_PROTO_MIN_PACKET_LENGTH, + 0); + } + return ZT_PROTO_MIN_PACKET_LENGTH * numPorts; + } + else { + ctx.cb.wirePacketSendFunction( + reinterpret_cast(ctx.node), + ctx.uPtr, + cc.tPtr, + -1, + reinterpret_cast(&atAddress), + p, + ZT_PROTO_MIN_PACKET_LENGTH, + 0); + return ZT_PROTO_MIN_PACKET_LENGTH; + } } void Peer::m_deriveSecondaryIdentityKeys() noexcept { - // This is called in init() and unmarshal() to use KBKDF to derive keys - // for encrypting the dictionary portion of HELLOs and HELLO HMAC from the - // primary long-lived identity key. + // This is called in init() and unmarshal() to use KBKDF to derive keys + // for encrypting the dictionary portion of HELLOs and HELLO HMAC from the + // primary long-lived identity key. - uint8_t hk[ZT_SYMMETRIC_KEY_SIZE]; - KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_HELLO_DICTIONARY_ENCRYPT, 0, 0, hk); - m_helloCipher.init(hk); - Utils::burn(hk, sizeof(hk)); + uint8_t hk[ZT_SYMMETRIC_KEY_SIZE]; + KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_HELLO_DICTIONARY_ENCRYPT, 0, 0, hk); + m_helloCipher.init(hk); + Utils::burn(hk, sizeof(hk)); - KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_PACKET_HMAC, 0, 0, m_helloMacKey); + KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_PACKET_HMAC, 0, 0, m_helloMacKey); } -unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const bool forceNewKey) +unsigned int Peer::m_hello( + const Context& ctx, + const CallContext& cc, + int64_t localSocket, + const InetAddress& atAddress, + const bool forceNewKey) { - // assumes m_lock is at least locked for reading + // assumes m_lock is at least locked for reading - /* SECURITY: note that HELLO is sent mostly in the clear and always uses - * the long-lived identity key. This allows us to always bootstrap regardless - * of ephemeral key state. HELLO contains nothing particularly sensitive, - * though part of the message is encrypted with another derived key just to - * conceal things like ephemeral public keys for defense in depth. HELLO is - * always sent with the old salsa/poly algorithm (but minus salsa of course - * as it's plaintext), but terminates with an additional HMAC-SHA3 - * authenticator to add extra hardness to the key exchange. The use of HMAC - * here is also needed to satisfy some FIPS/NIST type requirements. */ + /* SECURITY: note that HELLO is sent mostly in the clear and always uses + * the long-lived identity key. This allows us to always bootstrap regardless + * of ephemeral key state. HELLO contains nothing particularly sensitive, + * though part of the message is encrypted with another derived key just to + * conceal things like ephemeral public keys for defense in depth. HELLO is + * always sent with the old salsa/poly algorithm (but minus salsa of course + * as it's plaintext), but terminates with an additional HMAC-SHA3 + * authenticator to add extra hardness to the key exchange. The use of HMAC + * here is also needed to satisfy some FIPS/NIST type requirements. */ - // Pick or generate an ephemeral key to send with this HELLO. - p_EphemeralPrivate *ephemeral; - { - p_EphemeralPrivate *earliest = m_ephemeralKeysSent; - p_EphemeralPrivate *latest = nullptr; - int64_t earliestEphemeralPrivate = 9223372036854775807LL; - int64_t latestEphemeralPrivate = 0; - for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) { - const int64_t ct = m_ephemeralKeysSent[k].creationTime; - if (ct <= earliestEphemeralPrivate) { - earliestEphemeralPrivate = ct; - earliest = m_ephemeralKeysSent + k; - } else if (ct >= latestEphemeralPrivate) { // creationTime will be -1 if not initialized - latestEphemeralPrivate = ct; - latest = m_ephemeralKeysSent + k; - } - } + // Pick or generate an ephemeral key to send with this HELLO. + p_EphemeralPrivate* ephemeral; + { + p_EphemeralPrivate* earliest = m_ephemeralKeysSent; + p_EphemeralPrivate* latest = nullptr; + int64_t earliestEphemeralPrivate = 9223372036854775807LL; + int64_t latestEphemeralPrivate = 0; + for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) { + const int64_t ct = m_ephemeralKeysSent[k].creationTime; + if (ct <= earliestEphemeralPrivate) { + earliestEphemeralPrivate = ct; + earliest = m_ephemeralKeysSent + k; + } + else if (ct >= latestEphemeralPrivate) { // creationTime will be -1 if not initialized + latestEphemeralPrivate = ct; + latest = m_ephemeralKeysSent + k; + } + } - if ((latest != nullptr) && (!forceNewKey) && ((cc.ticks - latest->creationTime) < (ZT_SYMMETRIC_KEY_TTL / 2))) { - ephemeral = latest; - } else { - earliest->creationTime = cc.ticks; - earliest->pub.type = ZT_PROTO_EPHEMERAL_KEY_TYPE_C25519_P384; - C25519::generateC25519(earliest->pub.c25519Public, earliest->c25519Private); - ECC384GenerateKey(earliest->pub.p384Public, earliest->p384Private); - SHA384(earliest->sha384OfPublic, &earliest->pub, sizeof(earliest->pub)); - ephemeral = earliest; - } - } + if ((latest != nullptr) && (! forceNewKey) + && ((cc.ticks - latest->creationTime) < (ZT_SYMMETRIC_KEY_TTL / 2))) { + ephemeral = latest; + } + else { + earliest->creationTime = cc.ticks; + earliest->pub.type = ZT_PROTO_EPHEMERAL_KEY_TYPE_C25519_P384; + C25519::generateC25519(earliest->pub.c25519Public, earliest->c25519Private); + ECC384GenerateKey(earliest->pub.p384Public, earliest->p384Private); + SHA384(earliest->sha384OfPublic, &earliest->pub, sizeof(earliest->pub)); + ephemeral = earliest; + } + } - // Initialize packet and add basic fields like identity and sent-to address. - Buf outp; - const uint64_t packetId = m_identityKey.nextMessage(ctx.identity.address(), m_id.address()); - int ii = Protocol::newPacket(outp, packetId, m_id.address(), ctx.identity.address(), Protocol::VERB_HELLO); - outp.wI8(ii, ZT_PROTO_VERSION); - outp.wI8(ii, ZEROTIER_VERSION_MAJOR); - outp.wI8(ii, ZEROTIER_VERSION_MINOR); - outp.wI16(ii, ZEROTIER_VERSION_REVISION); - outp.wI64(ii, (uint64_t)cc.clock); - outp.wO(ii, ctx.identity); - outp.wO(ii, atAddress); + // Initialize packet and add basic fields like identity and sent-to address. + Buf outp; + const uint64_t packetId = m_identityKey.nextMessage(ctx.identity.address(), m_id.address()); + int ii = Protocol::newPacket(outp, packetId, m_id.address(), ctx.identity.address(), Protocol::VERB_HELLO); + outp.wI8(ii, ZT_PROTO_VERSION); + outp.wI8(ii, ZEROTIER_VERSION_MAJOR); + outp.wI8(ii, ZEROTIER_VERSION_MINOR); + outp.wI16(ii, ZEROTIER_VERSION_REVISION); + outp.wI64(ii, (uint64_t)cc.clock); + outp.wO(ii, ctx.identity); + outp.wO(ii, atAddress); - // Add 12 random bytes to act as an IV for the encrypted dictionary field. - const int ivStart = ii; - outp.wR(ii, 12); + // Add 12 random bytes to act as an IV for the encrypted dictionary field. + const int ivStart = ii; + outp.wR(ii, 12); - // LEGACY: the six reserved bytes after the IV exist for legacy compatibility with v1.x nodes. - // Once those are dead they'll become just reserved bytes for future use as flags etc. - outp.wI32(ii, 0); // reserved bytes - void *const legacyMoonCountStart = outp.unsafeData + ii; - outp.wI16(ii, 0); - const uint64_t legacySalsaIv = packetId & ZT_CONST_TO_BE_UINT64(0xfffffffffffffff8ULL); - Salsa20(m_identityKey.key(), &legacySalsaIv).crypt12(legacyMoonCountStart, legacyMoonCountStart, 2); + // LEGACY: the six reserved bytes after the IV exist for legacy compatibility with v1.x nodes. + // Once those are dead they'll become just reserved bytes for future use as flags etc. + outp.wI32(ii, 0); // reserved bytes + void* const legacyMoonCountStart = outp.unsafeData + ii; + outp.wI16(ii, 0); + const uint64_t legacySalsaIv = packetId & ZT_CONST_TO_BE_UINT64(0xfffffffffffffff8ULL); + Salsa20(m_identityKey.key(), &legacySalsaIv).crypt12(legacyMoonCountStart, legacyMoonCountStart, 2); - // Append dictionary containinig meta-data and ephemeral key info. - const int cryptSectionStart = ii; - FCV< uint8_t, 2048 > md; - Dictionary::append(md, ZT_PROTO_HELLO_NODE_META_INSTANCE_ID, ctx.instanceId); - // TODO: add other fields and ephemeral key info - outp.wI16(ii, (uint16_t)md.size()); - outp.wB(ii, md.data(), (unsigned int)md.size()); + // Append dictionary containinig meta-data and ephemeral key info. + const int cryptSectionStart = ii; + FCV md; + Dictionary::append(md, ZT_PROTO_HELLO_NODE_META_INSTANCE_ID, ctx.instanceId); + // TODO: add other fields and ephemeral key info + outp.wI16(ii, (uint16_t)md.size()); + outp.wB(ii, md.data(), (unsigned int)md.size()); - if (unlikely((ii + ZT_HMACSHA384_LEN) > ZT_BUF_SIZE)) // sanity check, should be impossible - return 0; + if (unlikely((ii + ZT_HMACSHA384_LEN) > ZT_BUF_SIZE)) // sanity check, should be impossible + return 0; - // Encrypt the meta-data dictionary using a derived static key and the IV - // we generated above. This isn't strictly necessary as the data in there is - // not "secret," but it's not a bad idea to hide it for defense in depth. In - // particular this means that the public keys exchanged for ephemeral keying - // are concealed from any observer. - AES::CTR ctr(m_helloCipher); - void *const cryptSection = outp.unsafeData + ii; - ctr.init(outp.unsafeData + ivStart, 0, cryptSection); - ctr.crypt(cryptSection, ii - cryptSectionStart); - ctr.finish(); + // Encrypt the meta-data dictionary using a derived static key and the IV + // we generated above. This isn't strictly necessary as the data in there is + // not "secret," but it's not a bad idea to hide it for defense in depth. In + // particular this means that the public keys exchanged for ephemeral keying + // are concealed from any observer. + AES::CTR ctr(m_helloCipher); + void* const cryptSection = outp.unsafeData + ii; + ctr.init(outp.unsafeData + ivStart, 0, cryptSection); + ctr.crypt(cryptSection, ii - cryptSectionStart); + ctr.finish(); - // Add HMAC at the end for strong verification by v2 nodes. - HMACSHA384(m_helloMacKey, outp.unsafeData, ii, outp.unsafeData + ii); - ii += ZT_HMACSHA384_LEN; + // Add HMAC at the end for strong verification by v2 nodes. + HMACSHA384(m_helloMacKey, outp.unsafeData, ii, outp.unsafeData + ii); + ii += ZT_HMACSHA384_LEN; - // Add poly1305 MAC for v1 nodes. - uint8_t polyKey[ZT_POLY1305_KEY_SIZE], perPacketKey[ZT_SALSA20_KEY_SIZE]; - Protocol::salsa2012DeriveKey(m_identityKey.key(), perPacketKey, outp, ii); - Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, polyKey, sizeof(polyKey)); - Poly1305 p1305(polyKey); - p1305.update(outp.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, ii - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START); - uint64_t polyMac[2]; - p1305.finish(polyMac); - Utils::storeMachineEndian< uint64_t >(outp.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, polyMac[0]); + // Add poly1305 MAC for v1 nodes. + uint8_t polyKey[ZT_POLY1305_KEY_SIZE], perPacketKey[ZT_SALSA20_KEY_SIZE]; + Protocol::salsa2012DeriveKey(m_identityKey.key(), perPacketKey, outp, ii); + Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, polyKey, sizeof(polyKey)); + Poly1305 p1305(polyKey); + p1305.update( + outp.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, + ii - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START); + uint64_t polyMac[2]; + p1305.finish(polyMac); + Utils::storeMachineEndian(outp.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, polyMac[0]); - return (likely(ctx.cb.wirePacketSendFunction(reinterpret_cast(ctx.node), ctx.uPtr, cc.tPtr, localSocket, reinterpret_cast(&atAddress), outp.unsafeData, ii, 0) == 0)) ? (unsigned int)ii : 0U; + return (likely( + ctx.cb.wirePacketSendFunction( + reinterpret_cast(ctx.node), + ctx.uPtr, + cc.tPtr, + localSocket, + reinterpret_cast(&atAddress), + outp.unsafeData, + ii, + 0) + == 0)) + ? (unsigned int)ii + : 0U; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Peer.hpp b/core/Peer.hpp index 358c9ecdc..1c9d8fd0e 100644 --- a/core/Peer.hpp +++ b/core/Peer.hpp @@ -14,36 +14,31 @@ #ifndef ZT_PEER_HPP #define ZT_PEER_HPP -#include "Constants.hpp" -#include "Context.hpp" -#include "Node.hpp" -#include "Path.hpp" +#include "AES.hpp" #include "Address.hpp" -#include "Utils.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Context.hpp" +#include "Endpoint.hpp" #include "Identity.hpp" #include "InetAddress.hpp" -#include "SharedPtr.hpp" -#include "Mutex.hpp" -#include "Endpoint.hpp" #include "Locator.hpp" +#include "Mutex.hpp" +#include "Node.hpp" +#include "Path.hpp" #include "Protocol.hpp" -#include "AES.hpp" +#include "SharedPtr.hpp" #include "SymmetricKey.hpp" -#include "Containers.hpp" +#include "Utils.hpp" -#define ZT_PEER_MARSHAL_SIZE_MAX ( \ - 1 + \ - ZT_ADDRESS_LENGTH + \ - ZT_SYMMETRIC_KEY_SIZE + \ - ZT_IDENTITY_MARSHAL_SIZE_MAX + \ - 1 + ZT_LOCATOR_MARSHAL_SIZE_MAX + \ - (2 * 4) + \ - 2 ) +#define ZT_PEER_MARSHAL_SIZE_MAX \ + (1 + ZT_ADDRESS_LENGTH + ZT_SYMMETRIC_KEY_SIZE + ZT_IDENTITY_MARSHAL_SIZE_MAX + 1 + ZT_LOCATOR_MARSHAL_SIZE_MAX \ + + (2 * 4) + 2) -#define ZT_PEER_DEDUP_BUFFER_SIZE 1024 -#define ZT_PEER_DEDUP_BUFFER_MASK 1023U +#define ZT_PEER_DEDUP_BUFFER_SIZE 1024 +#define ZT_PEER_DEDUP_BUFFER_MASK 1023U #define ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE 3 -#define ZT_PEER_EPHEMERAL_KEY_COUNT_MAX (ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE + 1) +#define ZT_PEER_EPHEMERAL_KEY_COUNT_MAX (ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE + 1) namespace ZeroTier { @@ -52,525 +47,567 @@ class Topology; /** * Peer on P2P Network (virtual layer 1) */ -class Peer -{ - friend class SharedPtr< Peer >; - friend class Topology; - -public: - /** - * Create an uninitialized peer - * - * New peers must be initialized via either init() or unmarshal() prior to - * use or null pointer dereference may occur. - */ - Peer(); - - ~Peer(); - - /** - * Initialize peer with an identity - * - * @param peerIdentity The peer's identity - * @return True if initialization was succcesful - */ - bool init(const Context &ctx, const CallContext &cc, const Identity &peerIdentity); - - /** - * @return This peer's ZT address (short for identity().address()) - */ - ZT_INLINE Address address() const noexcept - { return m_id.address(); } - - /** - * @return This peer's identity - */ - ZT_INLINE const Identity &identity() const noexcept - { return m_id; } - - /** - * @return Current locator or NULL if no locator is known - */ - ZT_INLINE const SharedPtr< const Locator > locator() const noexcept - { - RWMutex::RLock l(m_lock); - return m_locator; - } - - /** - * Set or update peer locator - * - * This checks the locator's timestamp against the current locator and - * replace it if newer. - * - * @param loc Locator update - * @param verify If true, verify locator's signature and structure - * @return New locator or previous if it was not replaced. - */ - ZT_INLINE SharedPtr< const Locator > setLocator(const SharedPtr< const Locator > &loc, const bool verify) noexcept - { - RWMutex::Lock l(m_lock); - if ((loc) && ((!m_locator) || (m_locator->revision() < loc->revision()))) { - if ((!verify) || loc->verify(m_id)) - m_locator = loc; - } - return m_locator; - } - - /** - * Log receipt of an authenticated packet - * - * This is called by the decode pipe when a packet is proven to be authentic - * and appears to be valid. - * - * @param path Path over which packet was received - * @param hops ZeroTier (not IP) hops - * @param packetId Packet ID - * @param verb Packet verb - * @param inReVerb In-reply verb for OK or ERROR verbs - */ - void received( - const Context &ctx, - const CallContext &cc, - const SharedPtr< Path > &path, - unsigned int hops, - uint64_t packetId, - unsigned int payloadLength, - Protocol::Verb verb, - Protocol::Verb inReVerb); - - /** - * Log sent data - * - * @param bytes Number of bytes written - */ - ZT_INLINE void sent(const CallContext &cc, const unsigned int bytes) noexcept - { - m_lastSend.store(cc.ticks, std::memory_order_relaxed); - m_outMeter.log(cc.ticks, bytes); - } - - /** - * Called when traffic destined for a different peer is sent to this one - * - * @param bytes Number of bytes relayed - */ - ZT_INLINE void relayed(const CallContext &cc, const unsigned int bytes) noexcept - { m_relayedMeter.log(cc.ticks, bytes); } - - /** - * Get the current best direct path or NULL if none - * - * @return Current best path or NULL if there is no direct path - */ - ZT_INLINE SharedPtr< Path > path(const CallContext &cc) noexcept - { return SharedPtr< Path >(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); } - - /** - * Send data to this peer over a specific path only - * - * @param data Data to send - * @param len Length in bytes - * @param via Path over which to send data (may or may not be an already-learned path for this peer) - */ - ZT_INLINE void send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len, const SharedPtr< Path > &via) noexcept - { - via->send(ctx, cc, data, len); - sent(cc, len); - } - - /** - * Send data to this peer over the best available path - * - * If there is a working direct path it will be used. Otherwise the data will be - * sent via a root server. - * - * @param data Data to send - * @param len Length in bytes - */ - void send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept; - - /** - * Do ping, probes, re-keying, and keepalive with this peer, as needed. - */ - void pulse(const Context &ctx, const CallContext &cc); - - /** - * Attempt to contact this peer at a given endpoint. - * - * The attempt doesn't happen immediately. It's added to a queue for the - * next invocation of pulse(). - * - * @param ep Endpoint to attempt to contact - * @param tries Number of times to try (default: 1) - */ - void contact(const Context &ctx, const CallContext &cc, const Endpoint &ep, int tries = 1); - - /** - * Reset paths within a given IP scope and address family - * - * Resetting a path involves sending an ECHO to it and then deactivating - * it until or unless it responds. This is done when we detect a change - * to our external IP or another system change that might invalidate - * many or all current paths. - * - * @param scope IP scope - * @param inetAddressFamily Family e.g. AF_INET - */ - void resetWithinScope(const Context &ctx, const CallContext &cc, InetAddress::IpScope scope, int inetAddressFamily); - - /** - * @return Time of last receive of anything, whether direct or relayed - */ - ZT_INLINE int64_t lastReceive() const noexcept - { return m_lastReceive.load(std::memory_order_relaxed); } - - /** - * @return Average latency of all direct paths or -1 if no direct paths or unknown - */ - ZT_INLINE int latency() const noexcept - { - RWMutex::RLock l(m_lock); - int ltot = 0; - int lcnt = 0; - for (unsigned int i = 0; i < m_alivePathCount; ++i) { - int lat = m_paths[i]->latency(); - if (lat > 0) { - ltot += lat; - ++lcnt; - } - } - return (ltot > 0) ? (lcnt / ltot) : -1; - } - - /** - * @return Cipher suite that should be used to communicate with this peer - */ - ZT_INLINE uint8_t cipher() const noexcept - { - //if (m_vProto >= 11) - // return ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV; - return ZT_PROTO_CIPHER_POLY1305_SALSA2012; - } - - /** - * @return The permanent shared key for this peer computed by simple identity agreement - */ - ZT_INLINE SymmetricKey &identityKey() noexcept - { return m_identityKey; } - - /** - * @return AES instance for HELLO dictionary / encrypted section encryption/decryption - */ - ZT_INLINE const AES &identityHelloDictionaryEncryptionCipher() const noexcept - { return m_helloCipher; } - - /** - * @return Key for HMAC on HELLOs - */ - ZT_INLINE const uint8_t *identityHelloHmacKey() const noexcept - { return m_helloMacKey; } - - /** - * @return Raw identity key bytes - */ - ZT_INLINE const uint8_t *rawIdentityKey() const noexcept - { return m_identityKey.key(); } - - /** - * @return Current best key: either the latest ephemeral or the identity key - */ - ZT_INLINE SymmetricKey &key() noexcept - { return *reinterpret_cast(m_key.load(std::memory_order_relaxed)); } - - /** - * Get keys other than a key we have already tried. - * - * This is used when a packet arrives that doesn't decrypt with the preferred - * key. It fills notYetTried[] with other keys that haven't been tried yet, - * which can include the identity key and any older session keys. - * - * @param alreadyTried Key we've already tried or NULL if none - * @param notYetTried All keys known (long lived or session) other than alreadyTried - * @return Number of pointers written to notYetTried[] - */ - ZT_INLINE int getOtherKeys(const SymmetricKey *const alreadyTried, SymmetricKey *notYetTried[ZT_PEER_EPHEMERAL_KEY_COUNT_MAX]) noexcept - { - RWMutex::RLock l(m_lock); - int cnt = 0; - if (alreadyTried != &m_identityKey) - notYetTried[cnt++] = &m_identityKey; - for (unsigned int k=0;k 0; - } - - /** - * Get all paths - * - * @param paths Vector of paths with the first path being the current preferred path - */ - ZT_INLINE void getAllPaths(Vector< SharedPtr< Path > > &paths) const - { - RWMutex::RLock l(m_lock); - paths.assign(m_paths, m_paths + m_alivePathCount); - } - - /** - * Save the latest version of this peer to the data store - */ - void save(const Context &ctx, const CallContext &cc) const; - - static constexpr int marshalSizeMax() noexcept - { return ZT_PEER_MARSHAL_SIZE_MAX; } - - int marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept; - int unmarshal(const Context &ctx, int64_t ticks, const uint8_t *restrict data, int len) noexcept; - - /** - * Rate limit gate for inbound WHOIS requests - */ - ZT_INLINE bool rateGateInboundWhoisRequest(CallContext &cc) noexcept - { - if ((cc.ticks - m_lastWhoisRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_WHOIS_RATE_LIMIT) { - m_lastWhoisRequestReceived.store(cc.ticks, std::memory_order_relaxed); - return true; - } - return false; - } - - /** - * Rate limit gate for inbound ECHO requests - */ - ZT_INLINE bool rateGateEchoRequest(CallContext &cc) noexcept - { - if ((cc.ticks - m_lastEchoRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_GENERAL_RATE_LIMIT) { - m_lastEchoRequestReceived.store(cc.ticks, std::memory_order_relaxed); - return true; - } - return false; - } - - /** - * Rate limit gate for inbound probes - */ - ZT_INLINE bool rateGateProbeRequest(CallContext &cc) noexcept - { - if ((cc.ticks - m_lastProbeReceived.load(std::memory_order_relaxed)) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) { - m_lastProbeReceived.store(cc.ticks, std::memory_order_relaxed); - return true; - } - return false; - } - - /** - * Packet deduplication filter for incoming packets - * - * This flags a packet ID and returns true if the same packet ID was already - * flagged. This is done in an atomic operation if supported. - * - * @param packetId Packet ID to check/flag - * @return True if this is a duplicate - */ - ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept - { return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(packetId, std::memory_order_relaxed) == packetId; } - -private: - struct p_EphemeralPublic - { - uint8_t type; - uint8_t c25519Public[ZT_C25519_ECDH_PUBLIC_KEY_SIZE]; - uint8_t p384Public[ZT_ECC384_PUBLIC_KEY_SIZE]; - }; - - static_assert(sizeof(p_EphemeralPublic) == (1 + ZT_C25519_ECDH_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE), "p_EphemeralPublic has extra padding"); - - struct p_EphemeralPrivate - { - ZT_INLINE p_EphemeralPrivate() noexcept: creationTime(-1) - {} - - ZT_INLINE ~p_EphemeralPrivate() - { Utils::burn(this, sizeof(p_EphemeralPublic)); } - - int64_t creationTime; - uint64_t sha384OfPublic[6]; - p_EphemeralPublic pub; - uint8_t c25519Private[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]; - uint8_t p384Private[ZT_ECC384_PRIVATE_KEY_SIZE]; - }; - - struct p_EphemeralSession - { - ZT_INLINE p_EphemeralSession() noexcept: established(false) - {} - - uint64_t sha384OfPeerPublic[6]; - SymmetricKey key; - bool established; - }; - - void m_prioritizePaths(const CallContext &cc); - unsigned int m_sendProbe(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const uint16_t *ports, unsigned int numPorts); - void m_deriveSecondaryIdentityKeys() noexcept; - unsigned int m_hello(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, bool forceNewKey); - - // Guards all fields except those otherwise indicated (and atomics of course). - RWMutex m_lock; - - // Long lived key resulting from agreement with this peer's identity. - SymmetricKey m_identityKey; - - // Cipher for encrypting or decrypting the encrypted section of HELLO packets. - AES m_helloCipher; - - // Key for HELLO HMAC-SHA384 - uint8_t m_helloMacKey[ZT_SYMMETRIC_KEY_SIZE]; - - // Keys we have generated and sent. - p_EphemeralPrivate m_ephemeralKeysSent[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE]; - - // Sessions created when OK(HELLO) is received. - p_EphemeralSession m_ephemeralSessions[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE]; - - // Pointer to active key (SymmetricKey). - std::atomic< uintptr_t > m_key; - - // Flag indicating that we should rekey at next pulse(). - bool m_keyRenegotiationNeeded; - - // This peer's public identity. - Identity m_id; - - // This peer's most recent (by revision) locator, or NULL if none on file. - SharedPtr< const Locator > m_locator; - - // The last time something was received or sent. - std::atomic< int64_t > m_lastReceive; - std::atomic< int64_t > m_lastSend; - - // The last time we sent a full HELLO to this peer. - int64_t m_lastSentHello; // only checked while locked - - // The last time a WHOIS request was received from this peer (anti-DOS / anti-flood). - std::atomic< int64_t > m_lastWhoisRequestReceived; - - // The last time an ECHO request was received from this peer (anti-DOS / anti-flood). - std::atomic< int64_t > m_lastEchoRequestReceived; - - // The last time we got a probe from this peer. - std::atomic< int64_t > m_lastProbeReceived; - - // Deduplication buffer. - std::atomic< uint64_t > m_dedup[ZT_PEER_DEDUP_BUFFER_SIZE]; - - // Meters measuring actual bandwidth in, out, and relayed via this peer (mostly if this is a root). - Meter<> m_inMeter; - Meter<> m_outMeter; - Meter<> m_relayedMeter; +class Peer { + friend class SharedPtr; + friend class Topology; + + public: + /** + * Create an uninitialized peer + * + * New peers must be initialized via either init() or unmarshal() prior to + * use or null pointer dereference may occur. + */ + Peer(); + + ~Peer(); + + /** + * Initialize peer with an identity + * + * @param peerIdentity The peer's identity + * @return True if initialization was succcesful + */ + bool init(const Context& ctx, const CallContext& cc, const Identity& peerIdentity); + + /** + * @return This peer's ZT address (short for identity().address()) + */ + ZT_INLINE Address address() const noexcept + { + return m_id.address(); + } + + /** + * @return This peer's identity + */ + ZT_INLINE const Identity& identity() const noexcept + { + return m_id; + } + + /** + * @return Current locator or NULL if no locator is known + */ + ZT_INLINE const SharedPtr locator() const noexcept + { + RWMutex::RLock l(m_lock); + return m_locator; + } + + /** + * Set or update peer locator + * + * This checks the locator's timestamp against the current locator and + * replace it if newer. + * + * @param loc Locator update + * @param verify If true, verify locator's signature and structure + * @return New locator or previous if it was not replaced. + */ + ZT_INLINE SharedPtr setLocator(const SharedPtr& loc, const bool verify) noexcept + { + RWMutex::Lock l(m_lock); + if ((loc) && ((! m_locator) || (m_locator->revision() < loc->revision()))) { + if ((! verify) || loc->verify(m_id)) + m_locator = loc; + } + return m_locator; + } + + /** + * Log receipt of an authenticated packet + * + * This is called by the decode pipe when a packet is proven to be authentic + * and appears to be valid. + * + * @param path Path over which packet was received + * @param hops ZeroTier (not IP) hops + * @param packetId Packet ID + * @param verb Packet verb + * @param inReVerb In-reply verb for OK or ERROR verbs + */ + void received( + const Context& ctx, + const CallContext& cc, + const SharedPtr& path, + unsigned int hops, + uint64_t packetId, + unsigned int payloadLength, + Protocol::Verb verb, + Protocol::Verb inReVerb); + + /** + * Log sent data + * + * @param bytes Number of bytes written + */ + ZT_INLINE void sent(const CallContext& cc, const unsigned int bytes) noexcept + { + m_lastSend.store(cc.ticks, std::memory_order_relaxed); + m_outMeter.log(cc.ticks, bytes); + } + + /** + * Called when traffic destined for a different peer is sent to this one + * + * @param bytes Number of bytes relayed + */ + ZT_INLINE void relayed(const CallContext& cc, const unsigned int bytes) noexcept + { + m_relayedMeter.log(cc.ticks, bytes); + } + + /** + * Get the current best direct path or NULL if none + * + * @return Current best path or NULL if there is no direct path + */ + ZT_INLINE SharedPtr path(const CallContext& cc) noexcept + { + return SharedPtr(reinterpret_cast(m_bestPath.load(std::memory_order_acquire))); + } + + /** + * Send data to this peer over a specific path only + * + * @param data Data to send + * @param len Length in bytes + * @param via Path over which to send data (may or may not be an already-learned path for this peer) + */ + ZT_INLINE void + send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len, const SharedPtr& via) + noexcept + { + via->send(ctx, cc, data, len); + sent(cc, len); + } + + /** + * Send data to this peer over the best available path + * + * If there is a working direct path it will be used. Otherwise the data will be + * sent via a root server. + * + * @param data Data to send + * @param len Length in bytes + */ + void send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept; + + /** + * Do ping, probes, re-keying, and keepalive with this peer, as needed. + */ + void pulse(const Context& ctx, const CallContext& cc); + + /** + * Attempt to contact this peer at a given endpoint. + * + * The attempt doesn't happen immediately. It's added to a queue for the + * next invocation of pulse(). + * + * @param ep Endpoint to attempt to contact + * @param tries Number of times to try (default: 1) + */ + void contact(const Context& ctx, const CallContext& cc, const Endpoint& ep, int tries = 1); + + /** + * Reset paths within a given IP scope and address family + * + * Resetting a path involves sending an ECHO to it and then deactivating + * it until or unless it responds. This is done when we detect a change + * to our external IP or another system change that might invalidate + * many or all current paths. + * + * @param scope IP scope + * @param inetAddressFamily Family e.g. AF_INET + */ + void resetWithinScope(const Context& ctx, const CallContext& cc, InetAddress::IpScope scope, int inetAddressFamily); + + /** + * @return Time of last receive of anything, whether direct or relayed + */ + ZT_INLINE int64_t lastReceive() const noexcept + { + return m_lastReceive.load(std::memory_order_relaxed); + } + + /** + * @return Average latency of all direct paths or -1 if no direct paths or unknown + */ + ZT_INLINE int latency() const noexcept + { + RWMutex::RLock l(m_lock); + int ltot = 0; + int lcnt = 0; + for (unsigned int i = 0; i < m_alivePathCount; ++i) { + int lat = m_paths[i]->latency(); + if (lat > 0) { + ltot += lat; + ++lcnt; + } + } + return (ltot > 0) ? (lcnt / ltot) : -1; + } + + /** + * @return Cipher suite that should be used to communicate with this peer + */ + ZT_INLINE uint8_t cipher() const noexcept + { + // if (m_vProto >= 11) + // return ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV; + return ZT_PROTO_CIPHER_POLY1305_SALSA2012; + } + + /** + * @return The permanent shared key for this peer computed by simple identity agreement + */ + ZT_INLINE SymmetricKey& identityKey() noexcept + { + return m_identityKey; + } + + /** + * @return AES instance for HELLO dictionary / encrypted section encryption/decryption + */ + ZT_INLINE const AES& identityHelloDictionaryEncryptionCipher() const noexcept + { + return m_helloCipher; + } + + /** + * @return Key for HMAC on HELLOs + */ + ZT_INLINE const uint8_t* identityHelloHmacKey() const noexcept + { + return m_helloMacKey; + } + + /** + * @return Raw identity key bytes + */ + ZT_INLINE const uint8_t* rawIdentityKey() const noexcept + { + return m_identityKey.key(); + } + + /** + * @return Current best key: either the latest ephemeral or the identity key + */ + ZT_INLINE SymmetricKey& key() noexcept + { + return *reinterpret_cast(m_key.load(std::memory_order_relaxed)); + } + + /** + * Get keys other than a key we have already tried. + * + * This is used when a packet arrives that doesn't decrypt with the preferred + * key. It fills notYetTried[] with other keys that haven't been tried yet, + * which can include the identity key and any older session keys. + * + * @param alreadyTried Key we've already tried or NULL if none + * @param notYetTried All keys known (long lived or session) other than alreadyTried + * @return Number of pointers written to notYetTried[] + */ + ZT_INLINE int getOtherKeys( + const SymmetricKey* const alreadyTried, + SymmetricKey* notYetTried[ZT_PEER_EPHEMERAL_KEY_COUNT_MAX]) noexcept + { + RWMutex::RLock l(m_lock); + int cnt = 0; + if (alreadyTried != &m_identityKey) + notYetTried[cnt++] = &m_identityKey; + for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) { + SymmetricKey* const kk = &m_ephemeralSessions[k].key; + if (m_ephemeralSessions[k].established && (alreadyTried != kk)) + notYetTried[cnt++] = kk; + } + return cnt; + } + + /** + * Set a flag ordering a key renegotiation ASAP. + * + * This can be called if there's any hint of an issue with the current key. + * It's also called if any of the secondary possible keys returned by + * getOtherKeys() decrypt a valid packet, indicating a desynchronization + * in which key should be used. + */ + ZT_INLINE void setKeyRenegotiationNeeded() noexcept + { + RWMutex::Lock l(m_lock); + m_keyRenegotiationNeeded = true; + } + + /** + * Set the currently known remote version of this peer's client + * + * @param vproto Protocol version + * @param vmaj Major version + * @param vmin Minor version + * @param vrev Revision + */ + ZT_INLINE void + setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev) noexcept + { + RWMutex::Lock l(m_lock); + m_vProto = (uint16_t)vproto; + m_vMajor = (uint16_t)vmaj; + m_vMinor = (uint16_t)vmin; + m_vRevision = (uint16_t)vrev; + } + + /** + * Get the remote version of this peer. + * + * If false is returned, the value of the value-result variables is + * undefined. + * + * @param vProto Set to protocol version + * @param vMajor Set to major version + * @param vMinor Set to minor version + * @param vRevision Set to revision + * @return True if remote version is known + */ + ZT_INLINE bool remoteVersion(uint16_t& vProto, uint16_t& vMajor, uint16_t& vMinor, uint16_t& vRevision) + { + RWMutex::RLock l(m_lock); + return (((vProto = m_vProto) | (vMajor = m_vMajor) | (vMinor = m_vMinor) | (vRevision = m_vRevision)) != 0); + } + + /** + * @return True if there is at least one alive direct path + */ + ZT_INLINE bool directlyConnected() const noexcept + { + RWMutex::RLock l(m_lock); + return m_alivePathCount > 0; + } + + /** + * Get all paths + * + * @param paths Vector of paths with the first path being the current preferred path + */ + ZT_INLINE void getAllPaths(Vector >& paths) const + { + RWMutex::RLock l(m_lock); + paths.assign(m_paths, m_paths + m_alivePathCount); + } + + /** + * Save the latest version of this peer to the data store + */ + void save(const Context& ctx, const CallContext& cc) const; + + static constexpr int marshalSizeMax() noexcept + { + return ZT_PEER_MARSHAL_SIZE_MAX; + } + + int marshal(const Context& ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept; + int unmarshal(const Context& ctx, int64_t ticks, const uint8_t* restrict data, int len) noexcept; + + /** + * Rate limit gate for inbound WHOIS requests + */ + ZT_INLINE bool rateGateInboundWhoisRequest(CallContext& cc) noexcept + { + if ((cc.ticks - m_lastWhoisRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_WHOIS_RATE_LIMIT) { + m_lastWhoisRequestReceived.store(cc.ticks, std::memory_order_relaxed); + return true; + } + return false; + } + + /** + * Rate limit gate for inbound ECHO requests + */ + ZT_INLINE bool rateGateEchoRequest(CallContext& cc) noexcept + { + if ((cc.ticks - m_lastEchoRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_GENERAL_RATE_LIMIT) { + m_lastEchoRequestReceived.store(cc.ticks, std::memory_order_relaxed); + return true; + } + return false; + } + + /** + * Rate limit gate for inbound probes + */ + ZT_INLINE bool rateGateProbeRequest(CallContext& cc) noexcept + { + if ((cc.ticks - m_lastProbeReceived.load(std::memory_order_relaxed)) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) { + m_lastProbeReceived.store(cc.ticks, std::memory_order_relaxed); + return true; + } + return false; + } + + /** + * Packet deduplication filter for incoming packets + * + * This flags a packet ID and returns true if the same packet ID was already + * flagged. This is done in an atomic operation if supported. + * + * @param packetId Packet ID to check/flag + * @return True if this is a duplicate + */ + ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept + { + return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange( + packetId, + std::memory_order_relaxed) + == packetId; + } + + private: + struct p_EphemeralPublic { + uint8_t type; + uint8_t c25519Public[ZT_C25519_ECDH_PUBLIC_KEY_SIZE]; + uint8_t p384Public[ZT_ECC384_PUBLIC_KEY_SIZE]; + }; + + static_assert( + sizeof(p_EphemeralPublic) == (1 + ZT_C25519_ECDH_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE), + "p_EphemeralPublic has extra padding"); + + struct p_EphemeralPrivate { + ZT_INLINE p_EphemeralPrivate() noexcept : creationTime(-1) + { + } + + ZT_INLINE ~p_EphemeralPrivate() + { + Utils::burn(this, sizeof(p_EphemeralPublic)); + } + + int64_t creationTime; + uint64_t sha384OfPublic[6]; + p_EphemeralPublic pub; + uint8_t c25519Private[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]; + uint8_t p384Private[ZT_ECC384_PRIVATE_KEY_SIZE]; + }; + + struct p_EphemeralSession { + ZT_INLINE p_EphemeralSession() noexcept : established(false) + { + } + + uint64_t sha384OfPeerPublic[6]; + SymmetricKey key; + bool established; + }; + + void m_prioritizePaths(const CallContext& cc); + unsigned int m_sendProbe( + const Context& ctx, + const CallContext& cc, + int64_t localSocket, + const InetAddress& atAddress, + const uint16_t* ports, + unsigned int numPorts); + void m_deriveSecondaryIdentityKeys() noexcept; + unsigned int m_hello( + const Context& ctx, + const CallContext& cc, + int64_t localSocket, + const InetAddress& atAddress, + bool forceNewKey); + + // Guards all fields except those otherwise indicated (and atomics of course). + RWMutex m_lock; + + // Long lived key resulting from agreement with this peer's identity. + SymmetricKey m_identityKey; + + // Cipher for encrypting or decrypting the encrypted section of HELLO packets. + AES m_helloCipher; + + // Key for HELLO HMAC-SHA384 + uint8_t m_helloMacKey[ZT_SYMMETRIC_KEY_SIZE]; + + // Keys we have generated and sent. + p_EphemeralPrivate m_ephemeralKeysSent[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE]; + + // Sessions created when OK(HELLO) is received. + p_EphemeralSession m_ephemeralSessions[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE]; + + // Pointer to active key (SymmetricKey). + std::atomic m_key; + + // Flag indicating that we should rekey at next pulse(). + bool m_keyRenegotiationNeeded; + + // This peer's public identity. + Identity m_id; + + // This peer's most recent (by revision) locator, or NULL if none on file. + SharedPtr m_locator; + + // The last time something was received or sent. + std::atomic m_lastReceive; + std::atomic m_lastSend; + + // The last time we sent a full HELLO to this peer. + int64_t m_lastSentHello; // only checked while locked + + // The last time a WHOIS request was received from this peer (anti-DOS / anti-flood). + std::atomic m_lastWhoisRequestReceived; + + // The last time an ECHO request was received from this peer (anti-DOS / anti-flood). + std::atomic m_lastEchoRequestReceived; + + // The last time we got a probe from this peer. + std::atomic m_lastProbeReceived; + + // Deduplication buffer. + std::atomic m_dedup[ZT_PEER_DEDUP_BUFFER_SIZE]; + + // Meters measuring actual bandwidth in, out, and relayed via this peer (mostly if this is a root). + Meter<> m_inMeter; + Meter<> m_outMeter; + Meter<> m_relayedMeter; + + // Direct paths sorted in descending order of preference. + SharedPtr m_paths[ZT_MAX_PEER_NETWORK_PATHS]; - // Direct paths sorted in descending order of preference. - SharedPtr< Path > m_paths[ZT_MAX_PEER_NETWORK_PATHS]; + // Size of m_paths[] in non-NULL paths (max: MAX_PEER_NETWORK_PATHS). + unsigned int m_alivePathCount; - // Size of m_paths[] in non-NULL paths (max: MAX_PEER_NETWORK_PATHS). - unsigned int m_alivePathCount; + // Current best path (pointer to Path). + std::atomic m_bestPath; + + // For SharedPtr<> + std::atomic __refCount; - // Current best path (pointer to Path). - std::atomic m_bestPath; + struct p_TryQueueItem { + ZT_INLINE p_TryQueueItem() : target(), iteration(0) + { + } - // For SharedPtr<> - std::atomic< int > __refCount; + ZT_INLINE p_TryQueueItem(const Endpoint& t, int iter) : target(t), iteration(iter) + { + } - struct p_TryQueueItem - { - ZT_INLINE p_TryQueueItem() : - target(), - iteration(0) - {} + Endpoint target; + int iteration; + }; - ZT_INLINE p_TryQueueItem(const Endpoint &t, int iter) : - target(t), - iteration(iter) - {} + // Queue of endpoints to try. + List m_tryQueue; - Endpoint target; - int iteration; - }; + // Time each endpoint was last tried, for rate limiting. + Map m_lastTried; - // Queue of endpoints to try. - List< p_TryQueueItem > m_tryQueue; - - // Time each endpoint was last tried, for rate limiting. - Map< Endpoint, int64_t > m_lastTried; - - // Version of remote peer, if known. - uint16_t m_vProto; - uint16_t m_vMajor; - uint16_t m_vMinor; - uint16_t m_vRevision; + // Version of remote peer, if known. + uint16_t m_vProto; + uint16_t m_vMajor; + uint16_t m_vMinor; + uint16_t m_vRevision; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Poly1305.cpp b/core/Poly1305.cpp index 4fa8aa1c5..a2b217b07 100644 --- a/core/Poly1305.cpp +++ b/core/Poly1305.cpp @@ -6,439 +6,524 @@ Public domain. // Small modifications have been made for ZeroTier, but this code remains in the public domain. -#include "Constants.hpp" #include "Poly1305.hpp" + +#include "Constants.hpp" #include "Utils.hpp" #include #ifdef __WINDOWS__ -#pragma warning(disable: 4146) +#pragma warning(disable : 4146) #endif -#define U8TO64(p) Utils::loadLittleEndian(p) -#define U64TO8(p,v) Utils::storeLittleEndian(p,v) -#define U8TO32(p) Utils::loadLittleEndian(p) -#define U32TO8(p,v) Utils::storeLittleEndian(p,v) +#define U8TO64(p) Utils::loadLittleEndian(p) +#define U64TO8(p, v) Utils::storeLittleEndian(p, v) +#define U8TO32(p) Utils::loadLittleEndian(p) +#define U32TO8(p, v) Utils::storeLittleEndian(p, v) namespace ZeroTier { namespace { typedef struct poly1305_context { - size_t aligner; - unsigned char opaque[136]; + size_t aligner; + unsigned char opaque[136]; } poly1305_context; #ifdef ZT_HAVE_UINT128 #define MUL(out, x, y) out = ((uint128_t)x * y) -#define ADD(out, in) out += in +#define ADD(out, in) out += in #define ADDLO(out, in) out += in #define SHR(in, shift) (unsigned long long)(in >> (shift)) -#define LO(in) (unsigned long long)(in) +#define LO(in) (unsigned long long)(in) #define poly1305_block_size 16 typedef struct poly1305_state_internal_t { - unsigned long long r[3]; - unsigned long long h[3]; - unsigned long long pad[2]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; + unsigned long long r[3]; + unsigned long long h[3]; + unsigned long long pad[2]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; } poly1305_state_internal_t; -ZT_INLINE void poly1305_init(poly1305_context *ctx,const unsigned char key[32]) +ZT_INLINE void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long t0,t1; + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long long t0, t1; - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - t0 = U8TO64(&key[0]); - t1 = U8TO64(&key[8]); + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = U8TO64(&key[0]); + t1 = U8TO64(&key[8]); - st->r[0] = ( t0 ) & 0xffc0fffffff; - st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; - st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + st->r[0] = (t0)&0xffc0fffffff; + st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; - /* save pad for later */ - st->pad[0] = U8TO64(&key[16]); - st->pad[1] = U8TO64(&key[24]); + /* save pad for later */ + st->pad[0] = U8TO64(&key[16]); + st->pad[1] = U8TO64(&key[24]); - st->leftover = 0; - st->final = 0; + st->leftover = 0; + st->final = 0; } -void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) +void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) { - const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ - unsigned long long r0,r1,r2; - unsigned long long s1,s2; - unsigned long long h0,h1,h2; - uint128_t d0,d1,d2,d; + const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ + unsigned long long r0, r1, r2; + unsigned long long s1, s2; + unsigned long long h0, h1, h2; + uint128_t d0, d1, d2, d; - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; - s1 = r1 * (5 << 2); - s2 = r2 * (5 << 2); + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); - while (bytes >= poly1305_block_size) { - unsigned long long t0,t1; + while (bytes >= poly1305_block_size) { + unsigned long long t0, t1; - /* h += m[i] */ - t0 = U8TO64(&m[0]); - t1 = U8TO64(&m[8]); + /* h += m[i] */ + t0 = U8TO64(&m[0]); + t1 = U8TO64(&m[8]); - h0 += (( t0 ) & 0xfffffffffff); - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); - h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; + h0 += ((t0)&0xfffffffffff); + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); + h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; - /* h *= r */ - MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); - MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); - MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); + /* h *= r */ + MUL(d0, h0, r0); + MUL(d, h1, s2); + ADD(d0, d); + MUL(d, h2, s1); + ADD(d0, d); + MUL(d1, h0, r1); + MUL(d, h1, r0); + ADD(d1, d); + MUL(d, h2, s2); + ADD(d1, d); + MUL(d2, h0, r2); + MUL(d, h1, r1); + ADD(d2, d); + MUL(d, h2, r0); + ADD(d2, d); - /* (partial) h %= p */ - unsigned long long c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; - ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; - ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; - h1 += c; + /* (partial) h %= p */ + unsigned long long c = SHR(d0, 44); + h0 = LO(d0) & 0xfffffffffff; + ADDLO(d1, c); + c = SHR(d1, 44); + h1 = LO(d1) & 0xfffffffffff; + ADDLO(d2, c); + c = SHR(d2, 42); + h2 = LO(d2) & 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 = h0 & 0xfffffffffff; + h1 += c; - m += poly1305_block_size; - bytes -= poly1305_block_size; - } + m += poly1305_block_size; + bytes -= poly1305_block_size; + } - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; } -ZT_INLINE void poly1305_finish(poly1305_context *ctx,unsigned char mac[16]) +ZT_INLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long h0,h1,h2,c; - unsigned long long g0,g1,g2; - unsigned long long t0,t1; + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long long h0, h1, h2, c; + unsigned long long g0, g1, g2; + unsigned long long t0, t1; - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i] = 1; - for (i = i + 1; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i] = 1; + for (i = i + 1; i < poly1305_block_size; i++) + st->buffer[i] = 0; + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; - c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; - g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; - g2 = h2 + c - ((unsigned long long)1 << 42); - - /* select h if h < p, or h + -p if h >= p */ - c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; - g0 &= c; - g1 &= c; - g2 &= c; - c = ~c; - h0 = (h0 & c) | g0; - h1 = (h1 & c) | g1; - h2 = (h2 & c) | g2; - - /* h = (h + pad) */ - t0 = st->pad[0]; - t1 = st->pad[1]; - - h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; - - /* mac = h % (2^128) */ - h0 = ((h0 ) | (h1 << 44)); - h1 = ((h1 >> 20) | (h2 << 24)); - - U64TO8(&mac[0], h0); - U64TO8(&mac[8], h1); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->pad[0] = 0; - st->pad[1] = 0; -} - -#else // no uint128_t - -#define poly1305_block_size 16 - -typedef struct poly1305_state_internal_t { - unsigned long r[5]; - unsigned long h[5]; - unsigned long pad[4]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; -} poly1305_state_internal_t; - -ZT_INLINE void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) -{ - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; - st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; - st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; - st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; - st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - - /* save pad for later */ - st->pad[0] = U8TO32(&key[16]); - st->pad[1] = U8TO32(&key[20]); - st->pad[2] = U8TO32(&key[24]); - st->pad[3] = U8TO32(&key[28]); - - st->leftover = 0; - st->final = 0; -} - -void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) -{ - const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ - unsigned long r0,r1,r2,r3,r4; - unsigned long s1,s2,s3,s4; - unsigned long h0,h1,h2,h3,h4; - - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - r3 = st->r[3]; - r4 = st->r[4]; - - s1 = r1 * 5; - s2 = r2 * 5; - s3 = r3 * 5; - s4 = r4 * 5; - - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - while (bytes >= poly1305_block_size) { - /* h += m[i] */ - h0 += (U8TO32(m+ 0) ) & 0x3ffffff; - h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; - h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; - h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; - h4 += (U8TO32(m+12) >> 8) | hibit; - - /* h *= r */ - unsigned long long d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); - unsigned long long d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); - unsigned long long d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); - unsigned long long d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); - unsigned long long d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); - - /* (partial) h %= p */ - unsigned long c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; - d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; - d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; - d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; - d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; - h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; h1 += c; - m += poly1305_block_size; - bytes -= poly1305_block_size; - } + /* compute h + -p */ + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((unsigned long long)1 << 42); - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; - st->h[3] = h3; - st->h[4] = h4; + /* select h if h < p, or h + -p if h >= p */ + c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; + g0 &= c; + g1 &= c; + g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; + + /* h = (h + pad) */ + t0 = st->pad[0]; + t1 = st->pad[1]; + + h0 += ((t0)&0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += (((t1 >> 24)) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = ((h0) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + U64TO8(&mac[0], h0); + U64TO8(&mac[8], h1); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->pad[0] = 0; + st->pad[1] = 0; } -ZT_INLINE void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) +#else // no uint128_t + +#define poly1305_block_size 16 + +typedef struct poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +ZT_INLINE void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long h0,h1,h2,h3,h4,c; - unsigned long g0,g1,g2,g3,g4; - unsigned long long f; - unsigned long mask; + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i++] = 1; - for (; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (U8TO32(&key[0])) & 0x3ffffff; + st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03; + st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff; + st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; - c = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; - h1 += c; + /* save pad for later */ + st->pad[0] = U8TO32(&key[16]); + st->pad[1] = U8TO32(&key[20]); + st->pad[2] = U8TO32(&key[24]); + st->pad[3] = U8TO32(&key[28]); - /* compute h + -p */ - g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; - g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; - g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; - g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; - g4 = h4 + c - (1 << 26); - - /* select h if h < p, or h + -p if h >= p */ - mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; - g0 &= mask; - g1 &= mask; - g2 &= mask; - g3 &= mask; - g4 &= mask; - mask = ~mask; - h0 = (h0 & mask) | g0; - h1 = (h1 & mask) | g1; - h2 = (h2 & mask) | g2; - h3 = (h3 & mask) | g3; - h4 = (h4 & mask) | g4; - - /* h = h % (2^128) */ - h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; - h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; - h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; - h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - - /* mac = (h + pad) % (2^128) */ - f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; - f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; - f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; - f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; - - U32TO8(mac + 0, h0); - U32TO8(mac + 4, h1); - U32TO8(mac + 8, h2); - U32TO8(mac + 12, h3); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->r[3] = 0; - st->r[4] = 0; - st->pad[0] = 0; - st->pad[1] = 0; - st->pad[2] = 0; - st->pad[3] = 0; -} - -#endif // uint128_t or portable version? - -ZT_INLINE void poly1305_update(poly1305_context *ctx,const unsigned char *m,size_t bytes) noexcept -{ - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - size_t i; - - /* handle leftover */ - if (st->leftover) { - size_t want = (poly1305_block_size - st->leftover); - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - st->buffer[st->leftover + i] = m[i]; - bytes -= want; - m += want; - st->leftover += want; - if (st->leftover < poly1305_block_size) - return; - poly1305_blocks(st, st->buffer, poly1305_block_size); st->leftover = 0; - } - - /* process full blocks */ - if (bytes >= poly1305_block_size) { - size_t want = (bytes & ~(poly1305_block_size - 1)); - poly1305_blocks(st, m, want); - m += want; - bytes -= want; - } - - /* store leftover */ - if (bytes) { - for (i = 0; i < bytes; i++) - st->buffer[st->leftover + i] = m[i]; - st->leftover += bytes; - } + st->final = 0; } -} // anonymous namespace - -void Poly1305::init(const void *key) noexcept +void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) { - static_assert(sizeof(ctx) >= sizeof(poly1305_context),"buffer in class smaller than required structure size"); - poly1305_init(reinterpret_cast(&ctx),reinterpret_cast(key)); + const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ + unsigned long r0, r1, r2, r3, r4; + unsigned long s1, s2, s3, s4; + unsigned long h0, h1, h2, h3, h4; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (U8TO32(m + 0)) & 0x3ffffff; + h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m + 12) >> 8) | hibit; + + /* h *= r */ + unsigned long long d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + + ((unsigned long long)h4 * s1); + unsigned long long d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + + ((unsigned long long)h4 * s2); + unsigned long long d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + + ((unsigned long long)h4 * s3); + unsigned long long d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + + ((unsigned long long)h4 * s4); + unsigned long long d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + + ((unsigned long long)h4 * r0); + + /* (partial) h %= p */ + unsigned long c = (unsigned long)(d0 >> 26); + h0 = (unsigned long)d0 & 0x3ffffff; + d1 += c; + c = (unsigned long)(d1 >> 26); + h1 = (unsigned long)d1 & 0x3ffffff; + d2 += c; + c = (unsigned long)(d2 >> 26); + h2 = (unsigned long)d2 & 0x3ffffff; + d3 += c; + c = (unsigned long)(d3 >> 26); + h3 = (unsigned long)d3 & 0x3ffffff; + d4 += c; + c = (unsigned long)(d4 >> 26); + h4 = (unsigned long)d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; } -void Poly1305::update(const void *data,unsigned int len) noexcept +ZT_INLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) { - poly1305_update(reinterpret_cast(&ctx),reinterpret_cast(data),(size_t)len); + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long h0, h1, h2, h3, h4, c; + unsigned long g0, g1, g2, g3, g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) + st->buffer[i] = 0; + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1 << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long)h0 + st->pad[0]; + h0 = (unsigned long)f; + f = (unsigned long long)h1 + st->pad[1] + (f >> 32); + h1 = (unsigned long)f; + f = (unsigned long long)h2 + st->pad[2] + (f >> 32); + h2 = (unsigned long)f; + f = (unsigned long long)h3 + st->pad[3] + (f >> 32); + h3 = (unsigned long)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; } -void Poly1305::finish(void *auth) noexcept +#endif // uint128_t or portable version? + +ZT_INLINE void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes) noexcept { - poly1305_finish(reinterpret_cast(&ctx),reinterpret_cast(auth)); + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + size_t i; + + /* handle leftover */ + if (st->leftover) { + size_t want = (poly1305_block_size - st->leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + st->buffer[st->leftover + i] = m[i]; + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) + return; + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + size_t want = (bytes & ~(poly1305_block_size - 1)); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) + st->buffer[st->leftover + i] = m[i]; + st->leftover += bytes; + } } -} // namespace ZeroTier +} // anonymous namespace + +void Poly1305::init(const void* key) noexcept +{ + static_assert(sizeof(ctx) >= sizeof(poly1305_context), "buffer in class smaller than required structure size"); + poly1305_init(reinterpret_cast(&ctx), reinterpret_cast(key)); +} + +void Poly1305::update(const void* data, unsigned int len) noexcept +{ + poly1305_update( + reinterpret_cast(&ctx), + reinterpret_cast(data), + (size_t)len); +} + +void Poly1305::finish(void* auth) noexcept +{ + poly1305_finish(reinterpret_cast(&ctx), reinterpret_cast(auth)); +} + +} // namespace ZeroTier diff --git a/core/Poly1305.hpp b/core/Poly1305.hpp index 3efaeb79c..98c6cc4f8 100644 --- a/core/Poly1305.hpp +++ b/core/Poly1305.hpp @@ -22,34 +22,36 @@ namespace ZeroTier { /** * Poly1305 one-time MAC calculator */ -class Poly1305 -{ -public: - ZT_INLINE Poly1305() - {} +class Poly1305 { + public: + ZT_INLINE Poly1305() + { + } - ZT_INLINE Poly1305(const void *key) - { this->init(key); } + ZT_INLINE Poly1305(const void* key) + { + this->init(key); + } - void init(const void *key) noexcept; - void update(const void *data, unsigned int len) noexcept; - void finish(void *auth) noexcept; + void init(const void* key) noexcept; + void update(const void* data, unsigned int len) noexcept; + void finish(void* auth) noexcept; - static ZT_INLINE void compute(void *const auth, const void *const data, const unsigned int len, const void *const key) noexcept - { - Poly1305 p(key); - p.update(data, len); - p.finish(auth); - } + static ZT_INLINE void + compute(void* const auth, const void* const data, const unsigned int len, const void* const key) noexcept + { + Poly1305 p(key); + p.update(data, len); + p.finish(auth); + } -private: - struct - { - size_t aligner; - unsigned char opaque[136]; - } ctx; + private: + struct { + size_t aligner; + unsigned char opaque[136]; + } ctx; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Protocol.hpp b/core/Protocol.hpp index aaee812bb..aaf47c157 100644 --- a/core/Protocol.hpp +++ b/core/Protocol.hpp @@ -14,14 +14,14 @@ #ifndef ZT_PROTOCOL_HPP #define ZT_PROTOCOL_HPP -#include "Constants.hpp" #include "AES.hpp" -#include "Salsa20.hpp" -#include "Poly1305.hpp" -#include "LZ4.hpp" -#include "Buf.hpp" #include "Address.hpp" +#include "Buf.hpp" +#include "Constants.hpp" #include "Identity.hpp" +#include "LZ4.hpp" +#include "Poly1305.hpp" +#include "Salsa20.hpp" #include "SymmetricKey.hpp" /* @@ -245,15 +245,17 @@ #define ZT_PROTO_PACKET_MAC_INDEX 19 #define ZT_PROTO_PACKET_VERB_INDEX 27 -#define ZT_PROTO_HELLO_NODE_META_INSTANCE_ID "i" -#define ZT_PROTO_HELLO_NODE_META_LOCATOR "l" -#define ZT_PROTO_HELLO_NODE_META_SOFTWARE_VENDOR "s" -#define ZT_PROTO_HELLO_NODE_META_COMPLIANCE "c" -#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_PUBLIC "e" -#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_ACK "E" +#define ZT_PROTO_HELLO_NODE_META_INSTANCE_ID "i" +#define ZT_PROTO_HELLO_NODE_META_LOCATOR "l" +#define ZT_PROTO_HELLO_NODE_META_SOFTWARE_VENDOR "s" +#define ZT_PROTO_HELLO_NODE_META_COMPLIANCE "c" +#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_PUBLIC "e" +#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_ACK "E" static_assert(ZT_PROTO_MAX_PACKET_LENGTH < ZT_BUF_MEM_SIZE, "maximum packet length won't fit in Buf"); -static_assert(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START == (ZT_PROTO_MIN_PACKET_LENGTH - 1), "encrypted packet section must start right before protocol verb at one less than minimum packet size"); +static_assert( + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START == (ZT_PROTO_MIN_PACKET_LENGTH - 1), + "encrypted packet section must start right before protocol verb at one less than minimum packet size"); namespace ZeroTier { namespace Protocol { @@ -261,474 +263,473 @@ namespace Protocol { /** * Packet verb (message type) */ -enum Verb -{ - /** - * No operation - * - * This packet does nothing, but it is sometimes sent as a probe to - * trigger a HELLO exchange as the code will attempt HELLO when it - * receives a packet from an unidentified source. - */ - VERB_NOP = 0x00, +enum Verb { + /** + * No operation + * + * This packet does nothing, but it is sometimes sent as a probe to + * trigger a HELLO exchange as the code will attempt HELLO when it + * receives a packet from an unidentified source. + */ + VERB_NOP = 0x00, - /** - * Announcement of a node's existence and vitals: - * <[1] protocol version> - * <[1] software major version (optional, 0 if unspecified)> - * <[1] software minor version (optional, 0 if unspecified)> - * <[2] software revision (optional, 0 if unspecified)> - * <[8] timestamp> - * <[...] binary serialized full sender identity> - * <[...] physical destination of packet> - * <[12] 96-bit CTR IV> - * <[6] reserved bytes, currently used for legacy compatibility> - * [... start of encrypted section ...] - * <[2] 16-bit length of encrypted dictionary> - * <[...] encrypted dictionary> - * [... end of encrypted section ...] - * <[48] HMAC-SHA384 of packet> - * - * HELLO is sent to initiate a new pairing between two nodes and - * periodically to refresh information. - * - * HELLO is the only packet ever sent without whole payload encryption, - * though an inner encrypted envelope exists to obscure all fields that - * do not need to be sent in the clear. There is nothing in this - * encrypted section that would be catastrophic if it leaked, but it's - * good to proactively limit exposed information. - * - * Inner encryption is AES-CTR with a key derived using KBKDF and a - * label indicating this specific usage. A 96-bit CTR IV precedes this - * encrypted section. - * - * Authentication and encryption in HELLO and OK(HELLO) are always done - * with the long-lived identity key, not ephemeral shared keys. This - * is so ephemeral key negotiation can always occur on the first try - * even if things get out of sync e.g. by one side restarting. Nothing - * in HELLO is likely to be dangerous if decrypted later. - * - * HELLO and OK(HELLO) include an extra HMAC at the end of the packet. - * This authenticates them to a level of certainty beyond that afforded - * by regular AEAD. HMAC is computed over the whole packet prior to - * packet MAC and with the 3-bit hop count field masked as it is - * with regular packet AEAD, and it is then included in the regular - * packet MAC. - * - * LEGACY: for legacy reasons the MAC field of HELLO is a poly1305 - * MAC initialized in the same manner as 1.x. Since HMAC provides - * additional full 384-bit strength authentication this should not be - * a problem for FIPS. - * - * Several legacy fields are present as well for the benefit of 1.x nodes. - * These will go away and become simple reserved space once 1.x is no longer - * supported. Some are self-explanatory. The "encrypted zero" is rather - * strange. It's a 16-bit zero value encrypted using Salsa20/12 and the - * long-lived identity key shared by the two peers. It tells 1.x that an - * old encrypted field is no longer there and that it should stop parsing - * the packet at that point. - * - * 1.x does not understand the dictionary and HMAC fields, but it will - * ignore them due to the "encrypted zero" field indicating that the - * packet contains no more information. - * - * Dictionary fields (defines start with ZT_PROTO_HELLO_NODE_META_): - * - * INSTANCE_ID - a 64-bit unique value generated on each node start - * LOCATOR - signed record enumerating this node's trusted contact points - * EPHEMERAL_PUBLIC - Ephemeral public key(s) - * - * OK will contain EPHEMERAL_PUBLIC of the responding node and: - * - * EPHEMERAL_ACK - SHA384(EPHEMERAL_PUBLIC from HELLO) - * - * The following optional fields may also be present: - * - * PREFERRED_CIPHER - preferred symmetric encryption mode - * HOSTNAME - arbitrary short host name for this node - * ARCH - system architecture (CPU type, bits, etc.) - * OSNAME - system operating system name - * OSVERSION - operating system version - * CONTACT - arbitrary short contact information string for this node - * SOFTWARE_VENDOR - short name or description of vendor, such as a URL - * COMPLIANCE - bit mask containing bits for e.g. a FIPS-compliant node - * - * The timestamp field in OK is echoed but the others represent the sender - * of the OK and are not echoes from HELLO. The dictionary in OK typically - * only contains the EPHEMERAL fields, allowing the receiver of the OK to - * confirm that both sides know the correct keys and thus begin using the - * ephemeral shared secret to send packets. - * - * OK is sent encrypted with the usual AEAD, but still includes a full HMAC - * as well (inside the cryptographic envelope). - * - * OK payload: - * <[8] timestamp echoed from original HELLO> - * <[1] protocol version of responding node> - * <[1] software major version (optional)> - * <[1] software minor version (optional)> - * <[2] software revision (optional)> - * <[...] physical destination address of packet> - * <[2] 16-bit reserved field (zero for legacy compatibility)> - * <[2] 16-bit length of dictionary> - * <[...] dictionary> - * <[48] HMAC-SHA384 of plaintext packet> - */ - VERB_HELLO = 0x01, + /** + * Announcement of a node's existence and vitals: + * <[1] protocol version> + * <[1] software major version (optional, 0 if unspecified)> + * <[1] software minor version (optional, 0 if unspecified)> + * <[2] software revision (optional, 0 if unspecified)> + * <[8] timestamp> + * <[...] binary serialized full sender identity> + * <[...] physical destination of packet> + * <[12] 96-bit CTR IV> + * <[6] reserved bytes, currently used for legacy compatibility> + * [... start of encrypted section ...] + * <[2] 16-bit length of encrypted dictionary> + * <[...] encrypted dictionary> + * [... end of encrypted section ...] + * <[48] HMAC-SHA384 of packet> + * + * HELLO is sent to initiate a new pairing between two nodes and + * periodically to refresh information. + * + * HELLO is the only packet ever sent without whole payload encryption, + * though an inner encrypted envelope exists to obscure all fields that + * do not need to be sent in the clear. There is nothing in this + * encrypted section that would be catastrophic if it leaked, but it's + * good to proactively limit exposed information. + * + * Inner encryption is AES-CTR with a key derived using KBKDF and a + * label indicating this specific usage. A 96-bit CTR IV precedes this + * encrypted section. + * + * Authentication and encryption in HELLO and OK(HELLO) are always done + * with the long-lived identity key, not ephemeral shared keys. This + * is so ephemeral key negotiation can always occur on the first try + * even if things get out of sync e.g. by one side restarting. Nothing + * in HELLO is likely to be dangerous if decrypted later. + * + * HELLO and OK(HELLO) include an extra HMAC at the end of the packet. + * This authenticates them to a level of certainty beyond that afforded + * by regular AEAD. HMAC is computed over the whole packet prior to + * packet MAC and with the 3-bit hop count field masked as it is + * with regular packet AEAD, and it is then included in the regular + * packet MAC. + * + * LEGACY: for legacy reasons the MAC field of HELLO is a poly1305 + * MAC initialized in the same manner as 1.x. Since HMAC provides + * additional full 384-bit strength authentication this should not be + * a problem for FIPS. + * + * Several legacy fields are present as well for the benefit of 1.x nodes. + * These will go away and become simple reserved space once 1.x is no longer + * supported. Some are self-explanatory. The "encrypted zero" is rather + * strange. It's a 16-bit zero value encrypted using Salsa20/12 and the + * long-lived identity key shared by the two peers. It tells 1.x that an + * old encrypted field is no longer there and that it should stop parsing + * the packet at that point. + * + * 1.x does not understand the dictionary and HMAC fields, but it will + * ignore them due to the "encrypted zero" field indicating that the + * packet contains no more information. + * + * Dictionary fields (defines start with ZT_PROTO_HELLO_NODE_META_): + * + * INSTANCE_ID - a 64-bit unique value generated on each node start + * LOCATOR - signed record enumerating this node's trusted contact points + * EPHEMERAL_PUBLIC - Ephemeral public key(s) + * + * OK will contain EPHEMERAL_PUBLIC of the responding node and: + * + * EPHEMERAL_ACK - SHA384(EPHEMERAL_PUBLIC from HELLO) + * + * The following optional fields may also be present: + * + * PREFERRED_CIPHER - preferred symmetric encryption mode + * HOSTNAME - arbitrary short host name for this node + * ARCH - system architecture (CPU type, bits, etc.) + * OSNAME - system operating system name + * OSVERSION - operating system version + * CONTACT - arbitrary short contact information string for this node + * SOFTWARE_VENDOR - short name or description of vendor, such as a URL + * COMPLIANCE - bit mask containing bits for e.g. a FIPS-compliant node + * + * The timestamp field in OK is echoed but the others represent the sender + * of the OK and are not echoes from HELLO. The dictionary in OK typically + * only contains the EPHEMERAL fields, allowing the receiver of the OK to + * confirm that both sides know the correct keys and thus begin using the + * ephemeral shared secret to send packets. + * + * OK is sent encrypted with the usual AEAD, but still includes a full HMAC + * as well (inside the cryptographic envelope). + * + * OK payload: + * <[8] timestamp echoed from original HELLO> + * <[1] protocol version of responding node> + * <[1] software major version (optional)> + * <[1] software minor version (optional)> + * <[2] software revision (optional)> + * <[...] physical destination address of packet> + * <[2] 16-bit reserved field (zero for legacy compatibility)> + * <[2] 16-bit length of dictionary> + * <[...] dictionary> + * <[48] HMAC-SHA384 of plaintext packet> + */ + VERB_HELLO = 0x01, - /** - * Error response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[1] error code> - * <[...] error-dependent payload, may be empty> - * - * An ERROR that does not pertain to a specific packet will have its verb - * set to VERB_NOP and its packet ID set to zero. - */ - VERB_ERROR = 0x02, + /** + * Error response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[1] error code> + * <[...] error-dependent payload, may be empty> + * + * An ERROR that does not pertain to a specific packet will have its verb + * set to VERB_NOP and its packet ID set to zero. + */ + VERB_ERROR = 0x02, - /** - * Success response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[...] response-specific payload> - */ - VERB_OK = 0x03, + /** + * Success response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[...] response-specific payload> + */ + VERB_OK = 0x03, - /** - * Query an identity by address: - * <[5] address to look up> - * [<[...] additional addresses to look up> - * - * OK response payload: - * <[...] identity> - * <[...] locator> - * [... additional identity/locator pairs] - * - * If the address is not found, no response is generated. The semantics - * of WHOIS is similar to ARP and NDP in that persistent retrying can - * be performed. - * - * It is possible for an identity but a null/empty locator to be returned - * if no locator is known for a node. Older versions may omit the locator. - */ - VERB_WHOIS = 0x04, + /** + * Query an identity by address: + * <[5] address to look up> + * [<[...] additional addresses to look up> + * + * OK response payload: + * <[...] identity> + * <[...] locator> + * [... additional identity/locator pairs] + * + * If the address is not found, no response is generated. The semantics + * of WHOIS is similar to ARP and NDP in that persistent retrying can + * be performed. + * + * It is possible for an identity but a null/empty locator to be returned + * if no locator is known for a node. Older versions may omit the locator. + */ + VERB_WHOIS = 0x04, - /** - * Relay-mediated NAT traversal or firewall punching initiation: - * <[1] flags> - * <[5] ZeroTier address of other peer> - * <[2] 16-bit number of endpoints where peer might be reached> - * [<[...] endpoints to attempt>] - * - * Legacy packet format for pre-2.x peers: - * <[1] flags (unused, currently 0)> - * <[5] ZeroTier address of other peer> - * <[2] 16-bit protocol address port> - * <[1] protocol address length / type> - * <[...] protocol address (network byte order)> - * - * When a root or other peer is relaying messages, it can periodically send - * RENDEZVOUS to assist peers in establishing direct communication. - * - * Peers also directly exchange information via HELLO, so this serves as - * a second way for peers to learn about their possible locations. - * - * It also serves another function: temporal coordination of NAT traversal - * attempts. Some NATs traverse better if both sides first send "firewall - * opener" packets and then send real packets and if this exchange is - * coordinated in time so that the packets effectively pass each other in - * flight. - * - * No OK or ERROR is generated. - */ - VERB_RENDEZVOUS = 0x05, + /** + * Relay-mediated NAT traversal or firewall punching initiation: + * <[1] flags> + * <[5] ZeroTier address of other peer> + * <[2] 16-bit number of endpoints where peer might be reached> + * [<[...] endpoints to attempt>] + * + * Legacy packet format for pre-2.x peers: + * <[1] flags (unused, currently 0)> + * <[5] ZeroTier address of other peer> + * <[2] 16-bit protocol address port> + * <[1] protocol address length / type> + * <[...] protocol address (network byte order)> + * + * When a root or other peer is relaying messages, it can periodically send + * RENDEZVOUS to assist peers in establishing direct communication. + * + * Peers also directly exchange information via HELLO, so this serves as + * a second way for peers to learn about their possible locations. + * + * It also serves another function: temporal coordination of NAT traversal + * attempts. Some NATs traverse better if both sides first send "firewall + * opener" packets and then send real packets and if this exchange is + * coordinated in time so that the packets effectively pass each other in + * flight. + * + * No OK or ERROR is generated. + */ + VERB_RENDEZVOUS = 0x05, - /** - * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): - * <[8] 64-bit network ID> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * MAC addresses are derived from the packet's source and destination - * ZeroTier addresses. This is a shortened EXT_FRAME that elides full - * Ethernet framing and other optional flags and features when they - * are not necessary. - * - * ERROR may be generated if a membership certificate is needed for a - * closed network. Payload will be network ID. - */ - VERB_FRAME = 0x06, + /** + * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): + * <[8] 64-bit network ID> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * MAC addresses are derived from the packet's source and destination + * ZeroTier addresses. This is a shortened EXT_FRAME that elides full + * Ethernet framing and other optional flags and features when they + * are not necessary. + * + * ERROR may be generated if a membership certificate is needed for a + * closed network. Payload will be network ID. + */ + VERB_FRAME = 0x06, - /** - * Full Ethernet frame with MAC addressing and optional fields: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] destination MAC or all zero for destination node> - * <[6] source MAC or all zero for node of origin> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - Most significant bit of subtype (see below) - * 0x04 - Middle bit of subtype (see below) - * 0x08 - Least significant bit of subtype (see below) - * 0x10 - ACK requested in the form of OK(EXT_FRAME) - * - * Subtypes (0..7): - * 0x0 - Normal frame (bridging can be determined by checking MAC) - * 0x1 - TEEd outbound frame - * 0x2 - REDIRECTed outbound frame - * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) - * 0x4 - TEEd inbound frame - * 0x5 - REDIRECTed inbound frame - * 0x6 - WATCHed inbound frame - * 0x7 - (reserved for future use) - * - * An extended frame carries full MAC addressing, making it a - * superset of VERB_FRAME. If 0x20 is set then p2p or hub and - * spoke multicast propagation is requested. - * - * OK payload (if ACK flag is set): - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] destination MAC or all zero for destination node> - * <[6] source MAC or all zero for node of origin> - * <[2] 16-bit ethertype> - */ - VERB_EXT_FRAME = 0x07, + /** + * Full Ethernet frame with MAC addressing and optional fields: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] destination MAC or all zero for destination node> + * <[6] source MAC or all zero for node of origin> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * Flags: + * 0x01 - Certificate of network membership attached (DEPRECATED) + * 0x02 - Most significant bit of subtype (see below) + * 0x04 - Middle bit of subtype (see below) + * 0x08 - Least significant bit of subtype (see below) + * 0x10 - ACK requested in the form of OK(EXT_FRAME) + * + * Subtypes (0..7): + * 0x0 - Normal frame (bridging can be determined by checking MAC) + * 0x1 - TEEd outbound frame + * 0x2 - REDIRECTed outbound frame + * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) + * 0x4 - TEEd inbound frame + * 0x5 - REDIRECTed inbound frame + * 0x6 - WATCHed inbound frame + * 0x7 - (reserved for future use) + * + * An extended frame carries full MAC addressing, making it a + * superset of VERB_FRAME. If 0x20 is set then p2p or hub and + * spoke multicast propagation is requested. + * + * OK payload (if ACK flag is set): + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] destination MAC or all zero for destination node> + * <[6] source MAC or all zero for node of origin> + * <[2] 16-bit ethertype> + */ + VERB_EXT_FRAME = 0x07, - /** - * ECHO request (a.k.a. ping): - * <[...] arbitrary payload> - * - * This generates OK with a copy of the transmitted payload. No ERROR - * is generated. Response to ECHO requests is optional and ECHO may be - * ignored if a node detects a possible flood. - */ - VERB_ECHO = 0x08, + /** + * ECHO request (a.k.a. ping): + * <[...] arbitrary payload> + * + * This generates OK with a copy of the transmitted payload. No ERROR + * is generated. Response to ECHO requests is optional and ECHO may be + * ignored if a node detects a possible flood. + */ + VERB_ECHO = 0x08, - /** - * Announce interest in multicast group(s): - * <[8] 64-bit network ID> - * <[6] multicast Ethernet address> - * <[4] multicast additional distinguishing information (ADI)> - * [... additional tuples of network/address/adi ...] - * - * LIKEs may be sent to any peer, though a good implementation should - * restrict them to peers on the same network they're for and to network - * controllers and root servers. In the current network, root servers - * will provide the service of final multicast cache. - */ - VERB_MULTICAST_LIKE = 0x09, + /** + * Announce interest in multicast group(s): + * <[8] 64-bit network ID> + * <[6] multicast Ethernet address> + * <[4] multicast additional distinguishing information (ADI)> + * [... additional tuples of network/address/adi ...] + * + * LIKEs may be sent to any peer, though a good implementation should + * restrict them to peers on the same network they're for and to network + * controllers and root servers. In the current network, root servers + * will provide the service of final multicast cache. + */ + VERB_MULTICAST_LIKE = 0x09, - /** - * Network credentials push: - * [<[...] one or more certificates of membership>] - * <[1] 0x00, null byte marking end of COM array> - * <[2] 16-bit number of capabilities> - * <[...] one or more serialized Capability> - * <[2] 16-bit number of tags> - * <[...] one or more serialized Tags> - * <[2] 16-bit number of revocations> - * <[...] one or more serialized Revocations> - * <[2] 16-bit number of certificates of ownership> - * <[...] one or more serialized CertificateOfOwnership> - * - * This can be sent by anyone at any time to push network credentials. - * These will of course only be accepted if they are properly signed. - * Credentials can be for any number of networks. - * - * The use of a zero byte to terminate the COM section is for legacy - * backward compatibility. Newer fields are prefixed with a length. - * - * OK/ERROR are not generated. - */ - VERB_NETWORK_CREDENTIALS = 0x0a, + /** + * Network credentials push: + * [<[...] one or more certificates of membership>] + * <[1] 0x00, null byte marking end of COM array> + * <[2] 16-bit number of capabilities> + * <[...] one or more serialized Capability> + * <[2] 16-bit number of tags> + * <[...] one or more serialized Tags> + * <[2] 16-bit number of revocations> + * <[...] one or more serialized Revocations> + * <[2] 16-bit number of certificates of ownership> + * <[...] one or more serialized CertificateOfOwnership> + * + * This can be sent by anyone at any time to push network credentials. + * These will of course only be accepted if they are properly signed. + * Credentials can be for any number of networks. + * + * The use of a zero byte to terminate the COM section is for legacy + * backward compatibility. Newer fields are prefixed with a length. + * + * OK/ERROR are not generated. + */ + VERB_NETWORK_CREDENTIALS = 0x0a, - /** - * Network configuration request: - * <[8] 64-bit network ID> - * <[2] 16-bit length of request meta-data dictionary> - * <[...] string-serialized request meta-data> - * <[8] 64-bit revision of netconf we currently have> - * <[8] 64-bit timestamp of netconf we currently have> - * - * This message requests network configuration from a node capable of - * providing it. Responses can be sent as OK(NETWORK_CONFIG_REQUEST) - * or NETWORK_CONFIG messages. NETWORK_CONFIG can also be sent by - * network controllers or other nodes unsolicited. - * - * OK response payload: - * (same as VERB_NETWORK_CONFIG payload) - * - * ERROR response payload: - * <[8] 64-bit network ID> - */ - VERB_NETWORK_CONFIG_REQUEST = 0x0b, + /** + * Network configuration request: + * <[8] 64-bit network ID> + * <[2] 16-bit length of request meta-data dictionary> + * <[...] string-serialized request meta-data> + * <[8] 64-bit revision of netconf we currently have> + * <[8] 64-bit timestamp of netconf we currently have> + * + * This message requests network configuration from a node capable of + * providing it. Responses can be sent as OK(NETWORK_CONFIG_REQUEST) + * or NETWORK_CONFIG messages. NETWORK_CONFIG can also be sent by + * network controllers or other nodes unsolicited. + * + * OK response payload: + * (same as VERB_NETWORK_CONFIG payload) + * + * ERROR response payload: + * <[8] 64-bit network ID> + */ + VERB_NETWORK_CONFIG_REQUEST = 0x0b, - /** - * Network configuration data push: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit reserved field (legacy)> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * Network configurations can come from network controllers or theoretically - * any other node, but each chunk must be signed by the network controller - * that generated it originally. The config update ID is arbitrary and is merely - * used by the receiver to group chunks. Chunk indexes must be sequential and - * the total delivered chunks must yield a total network config equal to the - * specified total length. - * - * Flags: - * 0x01 - Use fast propagation -- rumor mill flood this chunk to other members - * - * An OK should be sent if the config is successfully received and - * accepted. - * - * OK payload: - * <[8] 64-bit network ID> - * <[8] 64-bit config update ID> - */ - VERB_NETWORK_CONFIG = 0x0c, + /** + * Network configuration data push: + * <[8] 64-bit network ID> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit reserved field (legacy)> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * Network configurations can come from network controllers or theoretically + * any other node, but each chunk must be signed by the network controller + * that generated it originally. The config update ID is arbitrary and is merely + * used by the receiver to group chunks. Chunk indexes must be sequential and + * the total delivered chunks must yield a total network config equal to the + * specified total length. + * + * Flags: + * 0x01 - Use fast propagation -- rumor mill flood this chunk to other members + * + * An OK should be sent if the config is successfully received and + * accepted. + * + * OK payload: + * <[8] 64-bit network ID> + * <[8] 64-bit config update ID> + */ + VERB_NETWORK_CONFIG = 0x0c, - /** - * Request endpoints for multicast distribution: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * <[4] 32-bit requested max number of multicast peers> - * - * This message asks a peer for additional known endpoints that have - * LIKEd a given multicast group. It's sent when the sender wishes - * to send multicast but does not have the desired number of recipient - * peers. - * - * OK response payload: (multiple OKs can be generated) - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * ERROR is not generated; queries that return no response are dropped. - */ - VERB_MULTICAST_GATHER = 0x0d, + /** + * Request endpoints for multicast distribution: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * <[4] 32-bit requested max number of multicast peers> + * + * This message asks a peer for additional known endpoints that have + * LIKEd a given multicast group. It's sent when the sender wishes + * to send multicast but does not have the desired number of recipient + * peers. + * + * OK response payload: (multiple OKs can be generated) + * <[8] 64-bit network ID> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * <[4] 32-bit total number of known members in this multicast group> + * <[2] 16-bit number of members enumerated in this packet> + * <[...] series of 5-byte ZeroTier addresses of enumerated members> + * + * ERROR is not generated; queries that return no response are dropped. + */ + VERB_MULTICAST_GATHER = 0x0d, - // Deprecated multicast frame message type. - VERB_MULTICAST_FRAME_deprecated = 0x0e, + // Deprecated multicast frame message type. + VERB_MULTICAST_FRAME_deprecated = 0x0e, - /** - * Push of potential endpoints for direct communication: - * <[2] 16-bit number of endpoints> - * <[...] endpoints> - * - * If the target node is pre-2.0 path records of the following format - * are sent instead of post-2.x endpoints: - * <[1] 8-bit path flags (zero)> - * <[2] length of extended path characteristics (0)> - * [<[...] extended path characteristics>] - * <[1] address type> - * <[1] address length in bytes> - * <[...] address> - * - * Recipients will add these endpoints to a queue of possible endpoints - * to try for a given peer. - * - * OK and ERROR are not generated. - */ - VERB_PUSH_DIRECT_PATHS = 0x10, + /** + * Push of potential endpoints for direct communication: + * <[2] 16-bit number of endpoints> + * <[...] endpoints> + * + * If the target node is pre-2.0 path records of the following format + * are sent instead of post-2.x endpoints: + * <[1] 8-bit path flags (zero)> + * <[2] length of extended path characteristics (0)> + * [<[...] extended path characteristics>] + * <[1] address type> + * <[1] address length in bytes> + * <[...] address> + * + * Recipients will add these endpoints to a queue of possible endpoints + * to try for a given peer. + * + * OK and ERROR are not generated. + */ + VERB_PUSH_DIRECT_PATHS = 0x10, - /** - * A message with arbitrary user-definable content: - * <[8] 64-bit arbitrary message type ID> - * [<[...] message payload>] - * - * This can be used to send arbitrary messages over VL1. It generates no - * OK or ERROR and has no special semantics outside of whatever the user - * (via the ZeroTier core API) chooses to give it. - * - * Message type IDs less than or equal to 65535 are reserved for use by - * ZeroTier, Inc. itself. We recommend making up random ones for your own - * implementations. - */ - VERB_USER_MESSAGE = 0x14, + /** + * A message with arbitrary user-definable content: + * <[8] 64-bit arbitrary message type ID> + * [<[...] message payload>] + * + * This can be used to send arbitrary messages over VL1. It generates no + * OK or ERROR and has no special semantics outside of whatever the user + * (via the ZeroTier core API) chooses to give it. + * + * Message type IDs less than or equal to 65535 are reserved for use by + * ZeroTier, Inc. itself. We recommend making up random ones for your own + * implementations. + */ + VERB_USER_MESSAGE = 0x14, - VERB_MULTICAST = 0x16, + VERB_MULTICAST = 0x16, - /** - * Encapsulate a full ZeroTier packet in another: - * <[...] raw encapsulated packet> - * - * Encapsulation exists to enable secure relaying as opposed to the usual - * "dumb" relaying. The latter is faster but secure relaying has roles - * where endpoint privacy is desired. - * - * Packet hop count is incremented as normal. - */ - VERB_ENCAP = 0x17 + /** + * Encapsulate a full ZeroTier packet in another: + * <[...] raw encapsulated packet> + * + * Encapsulation exists to enable secure relaying as opposed to the usual + * "dumb" relaying. The latter is faster but secure relaying has roles + * where endpoint privacy is desired. + * + * Packet hop count is incremented as normal. + */ + VERB_ENCAP = 0x17 - // protocol max: 0x1f + // protocol max: 0x1f }; #ifdef ZT_DEBUG_SPEW -static ZT_INLINE const char *verbName(const Verb v) noexcept +static ZT_INLINE const char* verbName(const Verb v) noexcept { - switch (v) { - case VERB_NOP: - return "NOP"; - case VERB_HELLO: - return "HELLO"; - case VERB_ERROR: - return "ERROR"; - case VERB_OK: - return "OK"; - case VERB_WHOIS: - return "WHOIS"; - case VERB_RENDEZVOUS: - return "RENDEZVOUS"; - case VERB_FRAME: - return "FRAME"; - case VERB_EXT_FRAME: - return "EXT_FRAME"; - case VERB_ECHO: - return "ECHO"; - case VERB_MULTICAST_LIKE: - return "MULTICAST_LIKE"; - case VERB_NETWORK_CREDENTIALS: - return "NETWORK_CREDENTIALS"; - case VERB_NETWORK_CONFIG_REQUEST: - return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG: - return "NETWORK_CONFIG"; - case VERB_MULTICAST_GATHER: - return "MULTICAST_GATHER"; - case VERB_MULTICAST_FRAME_deprecated: - return "MULTICAST_FRAME_deprecated"; - case VERB_PUSH_DIRECT_PATHS: - return "PUSH_DIRECT_PATHS"; - case VERB_USER_MESSAGE: - return "USER_MESSAGE"; - case VERB_MULTICAST: - return "MULTICAST"; - case VERB_ENCAP: - return "ENCAP"; - default: - return "(unknown)"; - } + switch (v) { + case VERB_NOP: + return "NOP"; + case VERB_HELLO: + return "HELLO"; + case VERB_ERROR: + return "ERROR"; + case VERB_OK: + return "OK"; + case VERB_WHOIS: + return "WHOIS"; + case VERB_RENDEZVOUS: + return "RENDEZVOUS"; + case VERB_FRAME: + return "FRAME"; + case VERB_EXT_FRAME: + return "EXT_FRAME"; + case VERB_ECHO: + return "ECHO"; + case VERB_MULTICAST_LIKE: + return "MULTICAST_LIKE"; + case VERB_NETWORK_CREDENTIALS: + return "NETWORK_CREDENTIALS"; + case VERB_NETWORK_CONFIG_REQUEST: + return "NETWORK_CONFIG_REQUEST"; + case VERB_NETWORK_CONFIG: + return "NETWORK_CONFIG"; + case VERB_MULTICAST_GATHER: + return "MULTICAST_GATHER"; + case VERB_MULTICAST_FRAME_deprecated: + return "MULTICAST_FRAME_deprecated"; + case VERB_PUSH_DIRECT_PATHS: + return "PUSH_DIRECT_PATHS"; + case VERB_USER_MESSAGE: + return "USER_MESSAGE"; + case VERB_MULTICAST: + return "MULTICAST"; + case VERB_ENCAP: + return "ENCAP"; + default: + return "(unknown)"; + } } #endif @@ -736,28 +737,27 @@ static ZT_INLINE const char *verbName(const Verb v) noexcept /** * Error codes used in ERROR packets. */ -enum ErrorCode -{ - /* Invalid request */ - ERROR_INVALID_REQUEST = 0x01, +enum ErrorCode { + /* Invalid request */ + ERROR_INVALID_REQUEST = 0x01, - /* Bad/unsupported protocol version */ - ERROR_BAD_PROTOCOL_VERSION = 0x02, + /* Bad/unsupported protocol version */ + ERROR_BAD_PROTOCOL_VERSION = 0x02, - /* Unknown object queried */ - ERROR_OBJ_NOT_FOUND = 0x03, + /* Unknown object queried */ + ERROR_OBJ_NOT_FOUND = 0x03, - /* Verb or use case not supported/enabled by this node */ - ERROR_UNSUPPORTED_OPERATION = 0x05, + /* Verb or use case not supported/enabled by this node */ + ERROR_UNSUPPORTED_OPERATION = 0x05, - /* Network access denied; updated credentials needed */ - ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, + /* Network access denied; updated credentials needed */ + ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, - /* Tried to join network, but you're not a member */ - ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ + /* Tried to join network, but you're not a member */ + ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ - /* Cannot deliver a forwarded ZeroTier packet (for any reason) */ - ERROR_CANNOT_DELIVER = 0x09 + /* Cannot deliver a forwarded ZeroTier packet (for any reason) */ + ERROR_CANNOT_DELIVER = 0x09 }; /** @@ -766,44 +766,41 @@ enum ErrorCode * This allows the node to know whether this is a normal frame or one generated * by a special tee or redirect type flow rule. */ -enum ExtFrameSubtype -{ - EXT_FRAME_SUBTYPE_NORMAL = 0x0, - EXT_FRAME_SUBTYPE_TEE_OUTBOUND = 0x1, - EXT_FRAME_SUBTYPE_REDIRECT_OUTBOUND = 0x2, - EXT_FRAME_SUBTYPE_WATCH_OUTBOUND = 0x3, - EXT_FRAME_SUBTYPE_TEE_INBOUND = 0x4, - EXT_FRAME_SUBTYPE_REDIRECT_INBOUND = 0x5, - EXT_FRAME_SUBTYPE_WATCH_INBOUND = 0x6 +enum ExtFrameSubtype { + EXT_FRAME_SUBTYPE_NORMAL = 0x0, + EXT_FRAME_SUBTYPE_TEE_OUTBOUND = 0x1, + EXT_FRAME_SUBTYPE_REDIRECT_OUTBOUND = 0x2, + EXT_FRAME_SUBTYPE_WATCH_OUTBOUND = 0x3, + EXT_FRAME_SUBTYPE_TEE_INBOUND = 0x4, + EXT_FRAME_SUBTYPE_REDIRECT_INBOUND = 0x5, + EXT_FRAME_SUBTYPE_WATCH_INBOUND = 0x6 }; /** * EXT_FRAME flags */ -enum ExtFrameFlag -{ - /** - * A certifiate of membership was included (no longer used but still accepted) - */ - EXT_FRAME_FLAG_COM_ATTACHED_deprecated = 0x01, +enum ExtFrameFlag { + /** + * A certifiate of membership was included (no longer used but still accepted) + */ + EXT_FRAME_FLAG_COM_ATTACHED_deprecated = 0x01, - // bits 0x02, 0x04, and 0x08 are occupied by the 3-bit ExtFrameSubtype value. + // bits 0x02, 0x04, and 0x08 are occupied by the 3-bit ExtFrameSubtype value. - /** - * An OK(EXT_FRAME) acknowledgement was requested by the sender. - */ - EXT_FRAME_FLAG_ACK_REQUESTED = 0x10 + /** + * An OK(EXT_FRAME) acknowledgement was requested by the sender. + */ + EXT_FRAME_FLAG_ACK_REQUESTED = 0x10 }; /** * NETWORK_CONFIG (or OK(NETWORK_CONFIG_REQUEST)) flags */ -enum NetworkConfigFlag -{ - /** - * Indicates that this network config chunk should be fast propagated via rumor mill flooding. - */ - NETWORK_CONFIG_FLAG_FAST_PROPAGATE = 0x01 +enum NetworkConfigFlag { + /** + * Indicates that this network config chunk should be fast propagated via rumor mill flooding. + */ + NETWORK_CONFIG_FLAG_FAST_PROPAGATE = 0x01 }; /** @@ -816,42 +813,47 @@ enum NetworkConfigFlag * @param in Input key (32 bytes) * @param out Output buffer (32 bytes) */ -static ZT_INLINE void salsa2012DeriveKey(const uint8_t *const in, uint8_t *const out, const Buf &packet, const unsigned int packetSize) noexcept +static ZT_INLINE void +salsa2012DeriveKey(const uint8_t* const in, uint8_t* const out, const Buf& packet, const unsigned int packetSize) + noexcept { - // IV and source/destination addresses. Using the addresses divides the - // key space into two halves-- A->B and B->A (since order will change). + // IV and source/destination addresses. Using the addresses divides the + // key space into two halves-- A->B and B->A (since order will change). #ifdef ZT_NO_UNALIGNED_ACCESS - for(int i=0;i<18;++i) - out[i] = in[i] ^ packet.unsafeData[i]; + for (int i = 0; i < 18; ++i) + out[i] = in[i] ^ packet.unsafeData[i]; #else - *reinterpret_cast(out) = *reinterpret_cast(in) ^ *reinterpret_cast(packet.unsafeData); - *reinterpret_cast(out + 8) = *reinterpret_cast(in + 8) ^ *reinterpret_cast(packet.unsafeData + 8); - *reinterpret_cast(out + 16) = *reinterpret_cast(in + 16) ^ *reinterpret_cast(packet.unsafeData + 16); + *reinterpret_cast(out) = + *reinterpret_cast(in) ^ *reinterpret_cast(packet.unsafeData); + *reinterpret_cast(out + 8) = + *reinterpret_cast(in + 8) ^ *reinterpret_cast(packet.unsafeData + 8); + *reinterpret_cast(out + 16) = + *reinterpret_cast(in + 16) ^ *reinterpret_cast(packet.unsafeData + 16); #endif - // Flags, but with hop count masked off. Hop count is altered by forwarding - // nodes and is the only field that is mutable by unauthenticated third parties. - out[18] = in[18] ^ (packet.unsafeData[18] & 0xf8U); + // Flags, but with hop count masked off. Hop count is altered by forwarding + // nodes and is the only field that is mutable by unauthenticated third parties. + out[18] = in[18] ^ (packet.unsafeData[18] & 0xf8U); - // Raw packet size in bytes -- thus each packet size defines a new key space. - out[19] = in[19] ^ (uint8_t)packetSize; - out[20] = in[20] ^ (uint8_t)(packetSize >> 8U); // little endian + // Raw packet size in bytes -- thus each packet size defines a new key space. + out[19] = in[19] ^ (uint8_t)packetSize; + out[20] = in[20] ^ (uint8_t)(packetSize >> 8U); // little endian - // Rest of raw key is used unchanged + // Rest of raw key is used unchanged #ifdef ZT_NO_UNALIGNED_ACCESS - for(int i=21;i<32;++i) - out[i] = in[i]; + for (int i = 21; i < 32; ++i) + out[i] = in[i]; #else - out[21] = in[21]; - out[22] = in[22]; - out[23] = in[23]; - *reinterpret_cast(out + 24) = *reinterpret_cast(in + 24); + out[21] = in[21]; + out[22] = in[22]; + out[23] = in[23]; + *reinterpret_cast(out + 24) = *reinterpret_cast(in + 24); #endif } /** * Fill out packet header fields (except for mac, which is filled out by armor()) - * + * * @param pkt Start of packet buffer * @param packetId Packet IV / cryptographic MAC * @param destination Destination ZT address @@ -859,19 +861,24 @@ static ZT_INLINE void salsa2012DeriveKey(const uint8_t *const in, uint8_t *const * @param verb Protocol verb * @return Index of packet start */ -static ZT_INLINE int newPacket(uint8_t pkt[28], const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept +static ZT_INLINE int +newPacket(uint8_t pkt[28], const uint64_t packetId, const Address destination, const Address source, const Verb verb) + noexcept { - Utils::storeMachineEndian< uint64_t >(pkt + ZT_PROTO_PACKET_ID_INDEX, packetId); - destination.copyTo(pkt + ZT_PROTO_PACKET_DESTINATION_INDEX); - source.copyTo(pkt + ZT_PROTO_PACKET_SOURCE_INDEX); - pkt[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; - Utils::storeMachineEndian< uint64_t >(pkt + ZT_PROTO_PACKET_MAC_INDEX, 0); - pkt[ZT_PROTO_PACKET_VERB_INDEX] = (uint8_t)verb; - return ZT_PROTO_PACKET_VERB_INDEX + 1; + Utils::storeMachineEndian(pkt + ZT_PROTO_PACKET_ID_INDEX, packetId); + destination.copyTo(pkt + ZT_PROTO_PACKET_DESTINATION_INDEX); + source.copyTo(pkt + ZT_PROTO_PACKET_SOURCE_INDEX); + pkt[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; + Utils::storeMachineEndian(pkt + ZT_PROTO_PACKET_MAC_INDEX, 0); + pkt[ZT_PROTO_PACKET_VERB_INDEX] = (uint8_t)verb; + return ZT_PROTO_PACKET_VERB_INDEX + 1; } -static ZT_INLINE int newPacket(Buf &pkt, const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept -{ return newPacket(pkt.unsafeData, packetId, destination, source, verb); } +static ZT_INLINE int +newPacket(Buf& pkt, const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept +{ + return newPacket(pkt.unsafeData, packetId, destination, source, verb); +} /** * Encrypt and compute packet MAC @@ -882,9 +889,10 @@ static ZT_INLINE int newPacket(Buf &pkt, const uint64_t packetId, const Address * @param cipherSuite Cipher suite to use for AEAD encryption or just MAC * @return Packet ID of packet (which may change!) */ -static ZT_INLINE uint64_t armor(uint8_t *const pkt, const int packetSize, const SymmetricKey &key, const uint8_t cipherSuite) noexcept +static ZT_INLINE uint64_t +armor(uint8_t* const pkt, const int packetSize, const SymmetricKey& key, const uint8_t cipherSuite) noexcept { - // TODO + // TODO #if 0 Protocol::Header &ph = pkt.as(); // NOLINT(hicpp-use-auto,modernize-use-auto) ph.flags = (ph.flags & 0xc7U) | ((cipherSuite << 3U) & 0x38U); // flags: FFCCCHHH where CCC is cipher @@ -925,7 +933,7 @@ static ZT_INLINE uint64_t armor(uint8_t *const pkt, const int packetSize, const } break; } #endif - return 0; + return 0; } /** @@ -940,13 +948,13 @@ static ZT_INLINE uint64_t armor(uint8_t *const pkt, const int packetSize, const * @param packetSize Total size of packet in bytes (including headers) * @return New size of packet after compression or original size of compression wasn't helpful */ -static ZT_INLINE int compress(Buf &pkt, int packetSize) noexcept +static ZT_INLINE int compress(Buf& pkt, int packetSize) noexcept { - // TODO - return packetSize; + // TODO + return packetSize; } -} // namespace Protocol -} // namespace ZeroTier +} // namespace Protocol +} // namespace ZeroTier #endif diff --git a/core/README.md b/core/README.md index 49fb284c8..aa07a2636 100644 --- a/core/README.md +++ b/core/README.md @@ -7,7 +7,7 @@ Give it wire packets and it gives you Ethernet packets, and vice versa. The core Code in here follows these guidelines: - - Keep it minimal, especially in terms of code footprint and memory use. - - There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom). - - If it's not part of the core virtual Ethernet switch it does not belong here. - - Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems. +- Keep it minimal, especially in terms of code footprint and memory use. +- There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom). +- If it's not part of the core virtual Ethernet switch it does not belong here. +- Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems. diff --git a/core/RevocationCredential.cpp b/core/RevocationCredential.cpp index aff5f7935..bc778b798 100644 --- a/core/RevocationCredential.cpp +++ b/core/RevocationCredential.cpp @@ -15,78 +15,78 @@ namespace ZeroTier { -bool RevocationCredential::sign(const Identity &signer) noexcept +bool RevocationCredential::sign(const Identity& signer) noexcept { - uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32]; - if (signer.hasPrivate()) { - m_signedBy = signer.address(); - m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); - return true; - } - return false; + uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32]; + if (signer.hasPrivate()) { + m_signedBy = signer.address(); + m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); + return true; + } + return false; } int RevocationCredential::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign) const noexcept { - int p = 0; - if (forSign) { - for (int k = 0; k < 8; ++k) - data[p++] = 0x7f; - } - Utils::storeBigEndian< uint32_t >(data + p, 0); - Utils::storeBigEndian< uint32_t >(data + p + 4, m_id); - Utils::storeBigEndian< uint64_t >(data + p + 8, m_networkId); - Utils::storeBigEndian< uint32_t >(data + p + 16, 0); - Utils::storeBigEndian< uint32_t >(data + p + 20, m_credentialId); - Utils::storeBigEndian< uint64_t >(data + p + 24, (uint64_t)m_threshold); - Utils::storeBigEndian< uint64_t >(data + p + 32, m_flags); - p += 40; - m_target.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - m_signedBy.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - data[p++] = (uint8_t)m_type; - if (!forSign) { - data[p++] = 1; - Utils::storeBigEndian< uint16_t >(data + p, (uint16_t)m_signatureLength); - Utils::copy(data + p, m_signature, m_signatureLength); - p += (int)m_signatureLength; - } - data[p++] = 0; - data[p++] = 0; - if (forSign) { - for (int k = 0; k < 8; ++k) - data[p++] = 0x7f; - } - return p; + int p = 0; + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } + Utils::storeBigEndian(data + p, 0); + Utils::storeBigEndian(data + p + 4, m_id); + Utils::storeBigEndian(data + p + 8, m_networkId); + Utils::storeBigEndian(data + p + 16, 0); + Utils::storeBigEndian(data + p + 20, m_credentialId); + Utils::storeBigEndian(data + p + 24, (uint64_t)m_threshold); + Utils::storeBigEndian(data + p + 32, m_flags); + p += 40; + m_target.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + m_signedBy.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + data[p++] = (uint8_t)m_type; + if (! forSign) { + data[p++] = 1; + Utils::storeBigEndian(data + p, (uint16_t)m_signatureLength); + Utils::copy(data + p, m_signature, m_signatureLength); + p += (int)m_signatureLength; + } + data[p++] = 0; + data[p++] = 0; + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } + return p; } -int RevocationCredential::unmarshal(const uint8_t *restrict data, const int len) noexcept +int RevocationCredential::unmarshal(const uint8_t* restrict data, const int len) noexcept { - if (len < 54) - return -1; - // 4 bytes reserved - m_id = Utils::loadBigEndian< uint32_t >(data + 4); - m_networkId = Utils::loadBigEndian< uint64_t >(data + 8); - // 4 bytes reserved - m_credentialId = Utils::loadBigEndian< uint32_t >(data + 20); - m_threshold = (int64_t)Utils::loadBigEndian< uint64_t >(data + 24); - m_flags = Utils::loadBigEndian< uint64_t >(data + 32); - m_target.setTo(data + 40); - m_signedBy.setTo(data + 45); - m_type = (ZT_CredentialType)data[50]; - // 1 byte reserved - m_signatureLength = Utils::loadBigEndian< uint16_t >(data + 52); - int p = 54 + (int)m_signatureLength; - if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) - return -1; - Utils::copy(m_signature, data + 54, m_signatureLength); - if ((p + 2) > len) - return -1; - p += 2 + Utils::loadBigEndian< uint16_t >(data + p); - if (p > len) - return -1; - return p; + if (len < 54) + return -1; + // 4 bytes reserved + m_id = Utils::loadBigEndian(data + 4); + m_networkId = Utils::loadBigEndian(data + 8); + // 4 bytes reserved + m_credentialId = Utils::loadBigEndian(data + 20); + m_threshold = (int64_t)Utils::loadBigEndian(data + 24); + m_flags = Utils::loadBigEndian(data + 32); + m_target.setTo(data + 40); + m_signedBy.setTo(data + 45); + m_type = (ZT_CredentialType)data[50]; + // 1 byte reserved + m_signatureLength = Utils::loadBigEndian(data + 52); + int p = 54 + (int)m_signatureLength; + if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) + return -1; + Utils::copy(m_signature, data + 54, m_signatureLength); + if ((p + 2) > len) + return -1; + p += 2 + Utils::loadBigEndian(data + p); + if (p > len) + return -1; + return p; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/RevocationCredential.hpp b/core/RevocationCredential.hpp index bd8146d6a..545878f5f 100644 --- a/core/RevocationCredential.hpp +++ b/core/RevocationCredential.hpp @@ -14,12 +14,12 @@ #ifndef ZT_REVOCATION_HPP #define ZT_REVOCATION_HPP -#include "Constants.hpp" -#include "Credential.hpp" #include "Address.hpp" #include "C25519.hpp" -#include "Utils.hpp" +#include "Constants.hpp" +#include "Credential.hpp" #include "Identity.hpp" +#include "Utils.hpp" /** * Flag: fast propagation via rumor mill algorithm @@ -35,102 +35,138 @@ class Context; /** * Revocation certificate to instantaneously revoke a COM, capability, or tag */ -class RevocationCredential : public Credential -{ - friend class Credential; +class RevocationCredential : public Credential { + friend class Credential; -public: - static constexpr ZT_CredentialType credentialType() noexcept - { return ZT_CREDENTIAL_TYPE_REVOCATION; } + public: + static constexpr ZT_CredentialType credentialType() noexcept + { + return ZT_CREDENTIAL_TYPE_REVOCATION; + } - ZT_INLINE RevocationCredential() noexcept - { memoryZero(this); } + ZT_INLINE RevocationCredential() noexcept + { + memoryZero(this); + } - /** - * @param i ID (arbitrary for revocations, currently random) - * @param nwid Network ID - * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs) - * @param thr Revocation time threshold before which credentials will be revoked - * @param fl Flags - * @param tgt Target node whose credential(s) are being revoked - * @param ct Credential type being revoked - */ - ZT_INLINE RevocationCredential(const uint32_t i, const uint64_t nwid, const uint32_t cid, const uint64_t thr, const uint64_t fl, const Address &tgt, const ZT_CredentialType ct) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) - m_id(i), - m_credentialId(cid), - m_networkId(nwid), - m_threshold(thr), - m_flags(fl), - m_target(tgt), - m_signedBy(), - m_type(ct), - m_signatureLength(0) - {} + /** + * @param i ID (arbitrary for revocations, currently random) + * @param nwid Network ID + * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs) + * @param thr Revocation time threshold before which credentials will be revoked + * @param fl Flags + * @param tgt Target node whose credential(s) are being revoked + * @param ct Credential type being revoked + */ + ZT_INLINE RevocationCredential( + const uint32_t i, + const uint64_t nwid, + const uint32_t cid, + const uint64_t thr, + const uint64_t fl, + const Address& tgt, + const ZT_CredentialType ct) noexcept + : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + m_id(i) + , m_credentialId(cid) + , m_networkId(nwid) + , m_threshold(thr) + , m_flags(fl) + , m_target(tgt) + , m_signedBy() + , m_type(ct) + , m_signatureLength(0) + { + } - ZT_INLINE uint32_t id() const noexcept - { return m_id; } + ZT_INLINE uint32_t id() const noexcept + { + return m_id; + } - ZT_INLINE uint32_t credentialId() const noexcept - { return m_credentialId; } + ZT_INLINE uint32_t credentialId() const noexcept + { + return m_credentialId; + } - ZT_INLINE uint64_t networkId() const noexcept - { return m_networkId; } + ZT_INLINE uint64_t networkId() const noexcept + { + return m_networkId; + } - ZT_INLINE int64_t threshold() const noexcept - { return m_threshold; } + ZT_INLINE int64_t threshold() const noexcept + { + return m_threshold; + } - ZT_INLINE const Address &target() const noexcept - { return m_target; } + ZT_INLINE const Address& target() const noexcept + { + return m_target; + } - ZT_INLINE const Address &signer() const noexcept - { return m_signedBy; } + ZT_INLINE const Address& signer() const noexcept + { + return m_signedBy; + } - ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept - { return m_type; } + ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept + { + return m_type; + } - ZT_INLINE const uint8_t *signature() const noexcept - { return m_signature; } + ZT_INLINE const uint8_t* signature() const noexcept + { + return m_signature; + } - ZT_INLINE unsigned int signatureLength() const noexcept - { return m_signatureLength; } + ZT_INLINE unsigned int signatureLength() const noexcept + { + return m_signatureLength; + } - ZT_INLINE bool fastPropagate() const noexcept - { return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } + ZT_INLINE bool fastPropagate() const noexcept + { + return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); + } - /** - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - bool sign(const Identity &signer) noexcept; + /** + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + bool sign(const Identity& signer) noexcept; - /** - * Verify this revocation's signature - * - * @param RR Runtime environment to provide for peer lookup, etc. - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept - { return s_verify(ctx, cc, *this); } + /** + * Verify this revocation's signature + * + * @param RR Runtime environment to provide for peer lookup, etc. + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept + { + return s_verify(ctx, cc, *this); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_REVOCATION_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_REVOCATION_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; - int unmarshal(const uint8_t *restrict data, int len) noexcept; + int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; + int unmarshal(const uint8_t* restrict data, int len) noexcept; -private: - uint32_t m_id; - uint32_t m_credentialId; - uint64_t m_networkId; - int64_t m_threshold; - uint64_t m_flags; - Address m_target; - Address m_signedBy; - ZT_CredentialType m_type; - unsigned int m_signatureLength; - uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; + private: + uint32_t m_id; + uint32_t m_credentialId; + uint64_t m_networkId; + int64_t m_threshold; + uint64_t m_flags; + Address m_target; + Address m_signedBy; + ZT_CredentialType m_type; + unsigned int m_signatureLength; + uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/SHA512.cpp b/core/SHA512.cpp index ee28ed8bc..fb1116117 100644 --- a/core/SHA512.cpp +++ b/core/SHA512.cpp @@ -1,6 +1,7 @@ // This code is public domain, taken from a PD crypto source file on GitHub. #include "SHA512.hpp" + #include "Utils.hpp" namespace ZeroTier { @@ -10,265 +11,267 @@ namespace ZeroTier { namespace { struct sha512_state { - uint64_t length,state[8]; - unsigned long curlen; - uint8_t buf[128]; + uint64_t length, state[8]; + unsigned long curlen; + uint8_t buf[128]; }; static const uint64_t K[80] = { - 0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL, - 0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL, - 0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL, - 0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, + 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, + 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, + 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, + 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, + 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; -#define STORE64H(x, y) Utils::storeBigEndian(y,x) -#define LOAD64H(x, y) x = Utils::loadBigEndian(y) -#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y)))) -#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y)))) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR64c(x, n) -#define R(x, n) ((x)>>(n)) -#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) +#define STORE64H(x, y) Utils::storeBigEndian(y, x) +#define LOAD64H(x, y) x = Utils::loadBigEndian(y) +#define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y)))) +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) ((x) >> (n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf) +static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf) { - uint64_t S[8], W[80], t0, t1; - int i; + uint64_t S[8], W[80], t0, t1; + int i; - for (i = 0; i < 8; i++) - S[i] = md->state[i]; - for (i = 0; i < 16; i++) - LOAD64H(W[i], buf + (8*i)); - for (i = 16; i < 80; i++) - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + for (i = 0; i < 8; i++) + S[i] = md->state[i]; + for (i = 0; i < 16; i++) + LOAD64H(W[i], buf + (8 * i)); + for (i = 16; i < 80; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; +#define RND(a, b, c, d, e, f, g, h, i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; - for (i = 0; i < 80; i += 8) { - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); - } + for (i = 0; i < 80; i += 8) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0); + RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1); + RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2); + RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3); + RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4); + RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5); + RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6); + RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7); + } - for (i = 0; i < 8; i++) - md->state[i] = md->state[i] + S[i]; + for (i = 0; i < 8; i++) + md->state[i] = md->state[i] + S[i]; } -static ZT_INLINE void sha384_init(sha512_state *const md) +static ZT_INLINE void sha384_init(sha512_state* const md) { - md->curlen = 0; - md->length = 0; - md->state[0] = 0xcbbb9d5dc1059ed8ULL; - md->state[1] = 0x629a292a367cd507ULL; - md->state[2] = 0x9159015a3070dd17ULL; - md->state[3] = 0x152fecd8f70e5939ULL; - md->state[4] = 0x67332667ffc00b31ULL; - md->state[5] = 0x8eb44a8768581511ULL; - md->state[6] = 0xdb0c2e0d64f98fa7ULL; - md->state[7] = 0x47b5481dbefa4fa4ULL; + md->curlen = 0; + md->length = 0; + md->state[0] = 0xcbbb9d5dc1059ed8ULL; + md->state[1] = 0x629a292a367cd507ULL; + md->state[2] = 0x9159015a3070dd17ULL; + md->state[3] = 0x152fecd8f70e5939ULL; + md->state[4] = 0x67332667ffc00b31ULL; + md->state[5] = 0x8eb44a8768581511ULL; + md->state[6] = 0xdb0c2e0d64f98fa7ULL; + md->state[7] = 0x47b5481dbefa4fa4ULL; } -static ZT_INLINE void sha512_init(sha512_state *const md) +static ZT_INLINE void sha512_init(sha512_state* const md) { - md->curlen = 0; - md->length = 0; - md->state[0] = 0x6a09e667f3bcc908ULL; - md->state[1] = 0xbb67ae8584caa73bULL; - md->state[2] = 0x3c6ef372fe94f82bULL; - md->state[3] = 0xa54ff53a5f1d36f1ULL; - md->state[4] = 0x510e527fade682d1ULL; - md->state[5] = 0x9b05688c2b3e6c1fULL; - md->state[6] = 0x1f83d9abfb41bd6bULL; - md->state[7] = 0x5be0cd19137e2179ULL; + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6a09e667f3bcc908ULL; + md->state[1] = 0xbb67ae8584caa73bULL; + md->state[2] = 0x3c6ef372fe94f82bULL; + md->state[3] = 0xa54ff53a5f1d36f1ULL; + md->state[4] = 0x510e527fade682d1ULL; + md->state[5] = 0x9b05688c2b3e6c1fULL; + md->state[6] = 0x1f83d9abfb41bd6bULL; + md->state[7] = 0x5be0cd19137e2179ULL; } -static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen) +static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen) { - while (inlen > 0) { - if (md->curlen == 0 && inlen >= 128) { - sha512_compress(md,(uint8_t *)in); - md->length += 128 * 8; - in += 128; - inlen -= 128; - } else { - unsigned long n = std::min(inlen,(128 - md->curlen)); - Utils::copy(md->buf + md->curlen,in,n); - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == 128) { - sha512_compress(md,md->buf); - md->length += 8*128; - md->curlen = 0; - } - } - } + while (inlen > 0) { + if (md->curlen == 0 && inlen >= 128) { + sha512_compress(md, (uint8_t*)in); + md->length += 128 * 8; + in += 128; + inlen -= 128; + } + else { + unsigned long n = std::min(inlen, (128 - md->curlen)); + Utils::copy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == 128) { + sha512_compress(md, md->buf); + md->length += 8 * 128; + md->curlen = 0; + } + } + } } -static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out) +static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out) { - int i; + int i; - md->length += md->curlen * 8ULL; - md->buf[md->curlen++] = (uint8_t)0x80; + md->length += md->curlen * 8ULL; + md->buf[md->curlen++] = (uint8_t)0x80; - if (md->curlen > 112) { - while (md->curlen < 128) { - md->buf[md->curlen++] = (uint8_t)0; - } - sha512_compress(md, md->buf); - md->curlen = 0; - } + if (md->curlen > 112) { + while (md->curlen < 128) { + md->buf[md->curlen++] = (uint8_t)0; + } + sha512_compress(md, md->buf); + md->curlen = 0; + } - while (md->curlen < 120) { - md->buf[md->curlen++] = (uint8_t)0; - } + while (md->curlen < 120) { + md->buf[md->curlen++] = (uint8_t)0; + } - STORE64H(md->length, md->buf+120); - sha512_compress(md, md->buf); + STORE64H(md->length, md->buf + 120); + sha512_compress(md, md->buf); - for (i = 0; i < 8; i++) { - STORE64H(md->state[i], out+(8*i)); - } + for (i = 0; i < 8; i++) { + STORE64H(md->state[i], out + (8 * i)); + } } -} // anonymous namespace +} // anonymous namespace -void SHA512(void *digest,const void *data,unsigned int len) +void SHA512(void* digest, const void* data, unsigned int len) { - sha512_state state; - sha512_init(&state); - sha512_process(&state,(uint8_t *)data,(unsigned long)len); - sha512_done(&state,(uint8_t *)digest); + sha512_state state; + sha512_init(&state); + sha512_process(&state, (uint8_t*)data, (unsigned long)len); + sha512_done(&state, (uint8_t*)digest); } -void SHA384(void *digest,const void *data,unsigned int len) +void SHA384(void* digest, const void* data, unsigned int len) { - uint8_t tmp[64]; - sha512_state state; - sha384_init(&state); - sha512_process(&state,(uint8_t *)data,(unsigned long)len); - sha512_done(&state,tmp); - Utils::copy<48>(digest,tmp); + uint8_t tmp[64]; + sha512_state state; + sha384_init(&state); + sha512_process(&state, (uint8_t*)data, (unsigned long)len); + sha512_done(&state, tmp); + Utils::copy<48>(digest, tmp); } -void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) +void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1) { - uint8_t tmp[64]; - sha512_state state; - sha384_init(&state); - sha512_process(&state,(uint8_t *)data0,(unsigned long)len0); - sha512_process(&state,(uint8_t *)data1,(unsigned long)len1); - sha512_done(&state,tmp); - Utils::copy<48>(digest,tmp); + uint8_t tmp[64]; + sha512_state state; + sha384_init(&state); + sha512_process(&state, (uint8_t*)data0, (unsigned long)len0); + sha512_process(&state, (uint8_t*)data1, (unsigned long)len1); + sha512_done(&state, tmp); + Utils::copy<48>(digest, tmp); } -#endif // !ZT_HAVE_NATIVE_SHA512 +#endif // !ZT_HAVE_NATIVE_SHA512 -void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48]) +void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48]) { - uint64_t kInPadded[16]; // input padded key - uint64_t outer[22]; // output padded key | H(input padded key | msg) + uint64_t kInPadded[16]; // input padded key + uint64_t outer[22]; // output padded key | H(input padded key | msg) - const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key); - const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8); - const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16); - const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24); - const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32); - const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40); + const uint64_t k0 = Utils::loadMachineEndian(key); + const uint64_t k1 = Utils::loadMachineEndian(key + 8); + const uint64_t k2 = Utils::loadMachineEndian(key + 16); + const uint64_t k3 = Utils::loadMachineEndian(key + 24); + const uint64_t k4 = Utils::loadMachineEndian(key + 32); + const uint64_t k5 = Utils::loadMachineEndian(key + 40); - const uint64_t ipad = 0x3636363636363636ULL; - kInPadded[0] = k0 ^ ipad; - kInPadded[1] = k1 ^ ipad; - kInPadded[2] = k2 ^ ipad; - kInPadded[3] = k3 ^ ipad; - kInPadded[4] = k4 ^ ipad; - kInPadded[5] = k5 ^ ipad; - kInPadded[6] = ipad; - kInPadded[7] = ipad; - kInPadded[8] = ipad; - kInPadded[9] = ipad; - kInPadded[10] = ipad; - kInPadded[11] = ipad; - kInPadded[12] = ipad; - kInPadded[13] = ipad; - kInPadded[14] = ipad; - kInPadded[15] = ipad; + const uint64_t ipad = 0x3636363636363636ULL; + kInPadded[0] = k0 ^ ipad; + kInPadded[1] = k1 ^ ipad; + kInPadded[2] = k2 ^ ipad; + kInPadded[3] = k3 ^ ipad; + kInPadded[4] = k4 ^ ipad; + kInPadded[5] = k5 ^ ipad; + kInPadded[6] = ipad; + kInPadded[7] = ipad; + kInPadded[8] = ipad; + kInPadded[9] = ipad; + kInPadded[10] = ipad; + kInPadded[11] = ipad; + kInPadded[12] = ipad; + kInPadded[13] = ipad; + kInPadded[14] = ipad; + kInPadded[15] = ipad; - const uint64_t opad = 0x5c5c5c5c5c5c5c5cULL; - outer[0] = k0 ^ opad; - outer[1] = k1 ^ opad; - outer[2] = k2 ^ opad; - outer[3] = k3 ^ opad; - outer[4] = k4 ^ opad; - outer[5] = k5 ^ opad; - outer[6] = opad; - outer[7] = opad; - outer[8] = opad; - outer[9] = opad; - outer[10] = opad; - outer[11] = opad; - outer[12] = opad; - outer[13] = opad; - outer[14] = opad; - outer[15] = opad; + const uint64_t opad = 0x5c5c5c5c5c5c5c5cULL; + outer[0] = k0 ^ opad; + outer[1] = k1 ^ opad; + outer[2] = k2 ^ opad; + outer[3] = k3 ^ opad; + outer[4] = k4 ^ opad; + outer[5] = k5 ^ opad; + outer[6] = opad; + outer[7] = opad; + outer[8] = opad; + outer[9] = opad; + outer[10] = opad; + outer[11] = opad; + outer[12] = opad; + outer[13] = opad; + outer[14] = opad; + outer[15] = opad; - // H(output padded key | H(input padded key | msg)) - SHA384(reinterpret_cast(outer) + 128,kInPadded,128,msg,msglen); - SHA384(mac,outer,176); + // H(output padded key | H(input padded key | msg)) + SHA384(reinterpret_cast(outer) + 128, kInPadded, 128, msg, msglen); + SHA384(mac, outer, 176); } -void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) +void KBKDFHMACSHA384( + const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], + const char label, + const char context, + const uint32_t iter, + uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) { - uint8_t kbkdfMsg[13]; + uint8_t kbkdfMsg[13]; - Utils::storeBigEndian(kbkdfMsg,(uint32_t)iter); + Utils::storeBigEndian(kbkdfMsg, (uint32_t)iter); - kbkdfMsg[4] = (uint8_t)'Z'; - kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific - kbkdfMsg[6] = (uint8_t)label; - kbkdfMsg[7] = 0; + kbkdfMsg[4] = (uint8_t)'Z'; + kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific + kbkdfMsg[6] = (uint8_t)label; + kbkdfMsg[7] = 0; - kbkdfMsg[8] = (uint8_t)context; + kbkdfMsg[8] = (uint8_t)context; - // Output key length: 384 bits (as 32-bit big-endian value) - kbkdfMsg[9] = 0; - kbkdfMsg[10] = 0; - kbkdfMsg[11] = 0x01; - kbkdfMsg[12] = 0x80; + // Output key length: 384 bits (as 32-bit big-endian value) + kbkdfMsg[9] = 0; + kbkdfMsg[10] = 0; + kbkdfMsg[11] = 0x01; + kbkdfMsg[12] = 0x80; - static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE"); - HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out); + static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE"); + HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/SHA512.hpp b/core/SHA512.hpp index 410fa74ca..d6f8bd9ba 100644 --- a/core/SHA512.hpp +++ b/core/SHA512.hpp @@ -22,8 +22,8 @@ #define ZT_SHA512_DIGEST_SIZE 64 #define ZT_SHA384_DIGEST_SIZE 48 -#define ZT_SHA512_BLOCK_SIZE 128 -#define ZT_SHA384_BLOCK_SIZE 128 +#define ZT_SHA512_BLOCK_SIZE 128 +#define ZT_SHA384_BLOCK_SIZE 128 #define ZT_HMACSHA384_LEN 48 @@ -32,34 +32,34 @@ namespace ZeroTier { // SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS #ifdef __APPLE__ #define ZT_HAVE_NATIVE_SHA512 1 -static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len) +static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len) { - CC_SHA512_CTX ctx; - CC_SHA512_Init(&ctx); - CC_SHA512_Update(&ctx,data,len); - CC_SHA512_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA512_Init(&ctx); + CC_SHA512_Update(&ctx, data, len); + CC_SHA512_Final(reinterpret_cast(digest), &ctx); } -static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len) +static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len) { - CC_SHA512_CTX ctx; - CC_SHA384_Init(&ctx); - CC_SHA384_Update(&ctx,data,len); - CC_SHA384_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA384_Init(&ctx); + CC_SHA384_Update(&ctx, data, len); + CC_SHA384_Final(reinterpret_cast(digest), &ctx); } -static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) +static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1) { - CC_SHA512_CTX ctx; - CC_SHA384_Init(&ctx); - CC_SHA384_Update(&ctx,data0,len0); - CC_SHA384_Update(&ctx,data1,len1); - CC_SHA384_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA384_Init(&ctx); + CC_SHA384_Update(&ctx, data0, len0); + CC_SHA384_Update(&ctx, data1, len1); + CC_SHA384_Final(reinterpret_cast(digest), &ctx); } #endif #ifndef ZT_HAVE_NATIVE_SHA512 -void SHA512(void *digest,const void *data,unsigned int len); -void SHA384(void *digest,const void *data,unsigned int len); -void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1); +void SHA512(void* digest, const void* data, unsigned int len); +void SHA384(void* digest, const void* data, unsigned int len); +void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1); #endif /** @@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u * @param msglen Length of message * @param mac Buffer to fill with result */ -void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]); +void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]); /** * Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF @@ -81,8 +81,13 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne * @param iter Key iteration for generation of multiple keys for the same label/context * @param out Output to receive derived key */ -void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); +void KBKDFHMACSHA384( + const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], + char label, + char context, + uint32_t iter, + uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Salsa20.cpp b/core/Salsa20.cpp index a6fc51706..c2df00bd4 100644 --- a/core/Salsa20.cpp +++ b/core/Salsa20.cpp @@ -7,323 +7,353 @@ * Since the original was public domain, this is too. */ -#include "Constants.hpp" #include "Salsa20.hpp" +#include "Constants.hpp" + #define ROTATE(v, c) (((v) << (c)) | ((v) >> (32 - (c)))) -#define XOR(v, w) ((v) ^ (w)) -#define PLUS(v, w) ((uint32_t)((v) + (w))) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(v, w) ((uint32_t)((v) + (w))) #ifndef ZT_SALSA20_SSE #if __BYTE_ORDER == __LITTLE_ENDIAN #ifdef ZT_NO_UNALIGNED_ACCESS // Slower version that does not use type punning -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static ZT_INLINE void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } +#define U8TO32_LITTLE(p) \ + (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24)) +static ZT_INLINE void U32TO8_LITTLE(uint8_t* const c, const uint32_t v) +{ + c[0] = (uint8_t)v; + c[1] = (uint8_t)(v >> 8); + c[2] = (uint8_t)(v >> 16); + c[3] = (uint8_t)(v >> 24); +} #else // Fast version that just does 32-bit load/store -#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v) -#endif // ZT_NO_UNALIGNED_ACCESS -#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) +#define U8TO32_LITTLE(p) (*((const uint32_t*)((const void*)(p)))) +#define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = (v) +#endif // ZT_NO_UNALIGNED_ACCESS +#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) #ifdef __GNUC__ // Use GNUC builtin bswap macros on big-endian machines if available -#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = __builtin_bswap32((v)) -#else // no __GNUC__ +#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t*)((const void*)(p)))) +#define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = __builtin_bswap32((v)) +#else // no __GNUC__ // Otherwise do it the slow, manual way on BE machines -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static ZT_INLINE void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } -#endif // __GNUC__ or not -#endif // __BYTE_ORDER little or big? -#endif // !ZT_SALSA20_SSE +#define U8TO32_LITTLE(p) \ + (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24)) +static ZT_INLINE void U32TO8_LITTLE(uint8_t* const c, const uint32_t v) +{ + c[0] = (uint8_t)v; + c[1] = (uint8_t)(v >> 8); + c[2] = (uint8_t)(v >> 16); + c[3] = (uint8_t)(v >> 24); +} +#endif // __GNUC__ or not +#endif // __BYTE_ORDER little or big? +#endif // !ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE -class _s20sseconsts -{ -public: - _s20sseconsts() noexcept - { - maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); - maskHi32 = _mm_slli_epi64(maskLo32, 32); - } - __m128i maskLo32, maskHi32; +class _s20sseconsts { + public: + _s20sseconsts() noexcept + { + maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); + maskHi32 = _mm_slli_epi64(maskLo32, 32); + } + __m128i maskLo32, maskHi32; }; static const _s20sseconsts s_S20SSECONSTANTS; #endif namespace ZeroTier { -void Salsa20::init(const void *key, const void *iv) noexcept +void Salsa20::init(const void* key, const void* iv) noexcept { #ifdef ZT_SALSA20_SSE - const uint32_t *const k = (const uint32_t *)key; - _state.i[0] = 0x61707865; - _state.i[1] = 0x3320646e; - _state.i[2] = 0x79622d32; - _state.i[3] = 0x6b206574; - _state.i[4] = k[3]; - _state.i[5] = 0; - _state.i[6] = k[7]; - _state.i[7] = k[2]; - _state.i[8] = 0; - _state.i[9] = k[6]; - _state.i[10] = k[1]; - _state.i[11] = ((const uint32_t *)iv)[1]; - _state.i[12] = k[5]; - _state.i[13] = k[0]; - _state.i[14] = ((const uint32_t *)iv)[0]; - _state.i[15] = k[4]; + const uint32_t* const k = (const uint32_t*)key; + _state.i[0] = 0x61707865; + _state.i[1] = 0x3320646e; + _state.i[2] = 0x79622d32; + _state.i[3] = 0x6b206574; + _state.i[4] = k[3]; + _state.i[5] = 0; + _state.i[6] = k[7]; + _state.i[7] = k[2]; + _state.i[8] = 0; + _state.i[9] = k[6]; + _state.i[10] = k[1]; + _state.i[11] = ((const uint32_t*)iv)[1]; + _state.i[12] = k[5]; + _state.i[13] = k[0]; + _state.i[14] = ((const uint32_t*)iv)[0]; + _state.i[15] = k[4]; #else - const char *const constants = "expand 32-byte k"; - const uint8_t *const k = (const uint8_t *)key; - _state.i[0] = U8TO32_LITTLE(constants + 0); - _state.i[1] = U8TO32_LITTLE(k + 0); - _state.i[2] = U8TO32_LITTLE(k + 4); - _state.i[3] = U8TO32_LITTLE(k + 8); - _state.i[4] = U8TO32_LITTLE(k + 12); - _state.i[5] = U8TO32_LITTLE(constants + 4); - _state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0); - _state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4); - _state.i[8] = 0; - _state.i[9] = 0; - _state.i[10] = U8TO32_LITTLE(constants + 8); - _state.i[11] = U8TO32_LITTLE(k + 16); - _state.i[12] = U8TO32_LITTLE(k + 20); - _state.i[13] = U8TO32_LITTLE(k + 24); - _state.i[14] = U8TO32_LITTLE(k + 28); - _state.i[15] = U8TO32_LITTLE(constants + 12); + const char* const constants = "expand 32-byte k"; + const uint8_t* const k = (const uint8_t*)key; + _state.i[0] = U8TO32_LITTLE(constants + 0); + _state.i[1] = U8TO32_LITTLE(k + 0); + _state.i[2] = U8TO32_LITTLE(k + 4); + _state.i[3] = U8TO32_LITTLE(k + 8); + _state.i[4] = U8TO32_LITTLE(k + 12); + _state.i[5] = U8TO32_LITTLE(constants + 4); + _state.i[6] = U8TO32_LITTLE(((const uint8_t*)iv) + 0); + _state.i[7] = U8TO32_LITTLE(((const uint8_t*)iv) + 4); + _state.i[8] = 0; + _state.i[9] = 0; + _state.i[10] = U8TO32_LITTLE(constants + 8); + _state.i[11] = U8TO32_LITTLE(k + 16); + _state.i[12] = U8TO32_LITTLE(k + 20); + _state.i[13] = U8TO32_LITTLE(k + 24); + _state.i[14] = U8TO32_LITTLE(k + 28); + _state.i[15] = U8TO32_LITTLE(constants + 12); #endif } -union p_SalsaState -{ +union p_SalsaState { #ifdef ZT_SALSA20_SSE - __m128i v[4]; -#endif // ZT_SALSA20_SSE - uint32_t i[16]; + __m128i v[4]; +#endif // ZT_SALSA20_SSE + uint32_t i[16]; }; -template< unsigned int R > -static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m, uint8_t *c, unsigned int bytes) noexcept +template +static ZT_INLINE void p_salsaCrypt(p_SalsaState* const state, const uint8_t* m, uint8_t* c, unsigned int bytes) noexcept { - if (unlikely(bytes == 0)) - return; + if (unlikely(bytes == 0)) + return; - uint8_t tmp[64]; - uint8_t *ctarget = c; + uint8_t tmp[64]; + uint8_t* ctarget = c; #ifdef ZT_SALSA20_SSE - __m128i X0 = state->v[0]; - __m128i X1 = state->v[1]; - __m128i X2 = state->v[2]; - __m128i X3 = state->v[3]; - const __m128i maskLo32 = s_S20SSECONSTANTS.maskLo32; - const __m128i maskHi32 = s_S20SSECONSTANTS.maskHi32; - const __m128i add1 = _mm_set_epi32(0, 0, 0, 1); + __m128i X0 = state->v[0]; + __m128i X1 = state->v[1]; + __m128i X2 = state->v[2]; + __m128i X3 = state->v[3]; + const __m128i maskLo32 = s_S20SSECONSTANTS.maskLo32; + const __m128i maskHi32 = s_S20SSECONSTANTS.maskHi32; + const __m128i add1 = _mm_set_epi32(0, 0, 0, 1); #else - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - j0 = state->i[0]; - j1 = state->i[1]; - j2 = state->i[2]; - j3 = state->i[3]; - j4 = state->i[4]; - j5 = state->i[5]; - j6 = state->i[6]; - j7 = state->i[7]; - j8 = state->i[8]; - j9 = state->i[9]; - j10 = state->i[10]; - j11 = state->i[11]; - j12 = state->i[12]; - j13 = state->i[13]; - j14 = state->i[14]; - j15 = state->i[15]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + j0 = state->i[0]; + j1 = state->i[1]; + j2 = state->i[2]; + j3 = state->i[3]; + j4 = state->i[4]; + j5 = state->i[5]; + j6 = state->i[6]; + j7 = state->i[7]; + j8 = state->i[8]; + j9 = state->i[9]; + j10 = state->i[10]; + j11 = state->i[11]; + j12 = state->i[12]; + j13 = state->i[13]; + j14 = state->i[14]; + j15 = state->i[15]; #endif - for (;;) { - if (unlikely(bytes < 64)) { - for (unsigned int i = 0; i < bytes; ++i) - tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } + for (;;) { + if (unlikely(bytes < 64)) { + for (unsigned int i = 0; i < bytes; ++i) + tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } #ifdef ZT_SALSA20_SSE - __m128i X0s = X0; - __m128i X1s = X1; - __m128i X2s = X2; - __m128i X3s = X3; - __m128i T; + __m128i X0s = X0; + __m128i X1s = X1; + __m128i X2s = X2; + __m128i X3s = X3; + __m128i T; - for (unsigned int rr = 0; rr < (R / 2); ++rr) { - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - } + for (unsigned int rr = 0; rr < (R / 2); ++rr) { + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } - X0 = _mm_add_epi32(X0s, X0); - X1 = _mm_add_epi32(X1s, X1); - X2 = _mm_add_epi32(X2s, X2); - X3 = _mm_add_epi32(X3s, X3); + X0 = _mm_add_epi32(X0s, X0); + X1 = _mm_add_epi32(X1s, X1); + X2 = _mm_add_epi32(X2s, X2); + X3 = _mm_add_epi32(X3s, X3); - __m128i k02 = _mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)); - __m128i k20 = _mm_or_si128(_mm_and_si128(X2, maskLo32), _mm_and_si128(X1, maskHi32)); - __m128i k13 = _mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)); - __m128i k31 = _mm_or_si128(_mm_and_si128(X3, maskLo32), _mm_and_si128(X2, maskHi32)); - k02 = _mm_shuffle_epi32(k02, _MM_SHUFFLE(0, 1, 2, 3)); - k13 = _mm_shuffle_epi32(k13, _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k02 = _mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)); + __m128i k20 = _mm_or_si128(_mm_and_si128(X2, maskLo32), _mm_and_si128(X1, maskHi32)); + __m128i k13 = _mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)); + __m128i k31 = _mm_or_si128(_mm_and_si128(X3, maskLo32), _mm_and_si128(X2, maskHi32)); + k02 = _mm_shuffle_epi32(k02, _MM_SHUFFLE(0, 1, 2, 3)); + k13 = _mm_shuffle_epi32(k13, _MM_SHUFFLE(0, 1, 2, 3)); - _mm_storeu_si128(reinterpret_cast<__m128i *>(c), _mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_loadu_si128(reinterpret_cast(m)))); - _mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 1, _mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_loadu_si128(reinterpret_cast(m) + 1))); - _mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 2, _mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_loadu_si128(reinterpret_cast(m) + 2))); - _mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 3, _mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_loadu_si128(reinterpret_cast(m) + 3))); + _mm_storeu_si128( + reinterpret_cast<__m128i*>(c), + _mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_loadu_si128(reinterpret_cast(m)))); + _mm_storeu_si128( + reinterpret_cast<__m128i*>(c) + 1, + _mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_loadu_si128(reinterpret_cast(m) + 1))); + _mm_storeu_si128( + reinterpret_cast<__m128i*>(c) + 2, + _mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_loadu_si128(reinterpret_cast(m) + 2))); + _mm_storeu_si128( + reinterpret_cast<__m128i*>(c) + 3, + _mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_loadu_si128(reinterpret_cast(m) + 3))); - X0 = X0s; - X1 = X1s; - X2 = _mm_add_epi32(X2s, add1); - X3 = X3s; + X0 = X0s; + X1 = X1s; + X2 = _mm_add_epi32(X2s, add1); + X3 = X3s; #else - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; - for(unsigned int rr=0;rr<(R/2);++rr) { - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - } + for (unsigned int rr = 0; rr < (R / 2); ++rr) { + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); + } - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); - U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); - U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); - U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); - U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); - U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); - U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); - U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); - U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); - U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); - U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); - U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); - U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); - U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); - U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); - U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); - U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); + U32TO8_LITTLE(c + 0, XOR(x0, U8TO32_LITTLE(m + 0))); + U32TO8_LITTLE(c + 4, XOR(x1, U8TO32_LITTLE(m + 4))); + U32TO8_LITTLE(c + 8, XOR(x2, U8TO32_LITTLE(m + 8))); + U32TO8_LITTLE(c + 12, XOR(x3, U8TO32_LITTLE(m + 12))); + U32TO8_LITTLE(c + 16, XOR(x4, U8TO32_LITTLE(m + 16))); + U32TO8_LITTLE(c + 20, XOR(x5, U8TO32_LITTLE(m + 20))); + U32TO8_LITTLE(c + 24, XOR(x6, U8TO32_LITTLE(m + 24))); + U32TO8_LITTLE(c + 28, XOR(x7, U8TO32_LITTLE(m + 28))); + U32TO8_LITTLE(c + 32, XOR(x8, U8TO32_LITTLE(m + 32))); + U32TO8_LITTLE(c + 36, XOR(x9, U8TO32_LITTLE(m + 36))); + U32TO8_LITTLE(c + 40, XOR(x10, U8TO32_LITTLE(m + 40))); + U32TO8_LITTLE(c + 44, XOR(x11, U8TO32_LITTLE(m + 44))); + U32TO8_LITTLE(c + 48, XOR(x12, U8TO32_LITTLE(m + 48))); + U32TO8_LITTLE(c + 52, XOR(x13, U8TO32_LITTLE(m + 52))); + U32TO8_LITTLE(c + 56, XOR(x14, U8TO32_LITTLE(m + 56))); + U32TO8_LITTLE(c + 60, XOR(x15, U8TO32_LITTLE(m + 60))); - ++j8; + ++j8; #endif - if (likely(bytes > 64)) { - bytes -= 64; - c += 64; - m += 64; - } else { - if (bytes < 64) { - for (unsigned int i = 0; i < bytes; ++i) - ctarget[i] = c[i]; - } + if (likely(bytes > 64)) { + bytes -= 64; + c += 64; + m += 64; + } + else { + if (bytes < 64) { + for (unsigned int i = 0; i < bytes; ++i) + ctarget[i] = c[i]; + } #ifdef ZT_SALSA20_SSE - state->v[2] = X2; + state->v[2] = X2; #else - state->i[8] = j8; + state->i[8] = j8; #endif - return; - } - } + return; + } + } } -void Salsa20::crypt12(const void *in, void *out, unsigned int bytes) noexcept +void Salsa20::crypt12(const void* in, void* out, unsigned int bytes) noexcept { - p_salsaCrypt< 12 >(reinterpret_cast(&_state), reinterpret_cast(in), reinterpret_cast(out), bytes); + p_salsaCrypt<12>( + reinterpret_cast(&_state), + reinterpret_cast(in), + reinterpret_cast(out), + bytes); } -void Salsa20::crypt20(const void *in, void *out, unsigned int bytes) noexcept +void Salsa20::crypt20(const void* in, void* out, unsigned int bytes) noexcept { - p_salsaCrypt< 20 >(reinterpret_cast(&_state), reinterpret_cast(in), reinterpret_cast(out), bytes); + p_salsaCrypt<20>( + reinterpret_cast(&_state), + reinterpret_cast(in), + reinterpret_cast(out), + bytes); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Salsa20.hpp b/core/Salsa20.hpp index 7a3cc8c8a..846a56d46 100644 --- a/core/Salsa20.hpp +++ b/core/Salsa20.hpp @@ -15,8 +15,8 @@ #define ZT_SALSA20_HPP #include "Constants.hpp" -#include "Utils.hpp" #include "TriviallyCopyable.hpp" +#include "Utils.hpp" #ifdef ZT_ARCH_X64 #define ZT_SALSA20_SSE 1 @@ -35,67 +35,75 @@ namespace ZeroTier { * a minor optimization done here because ZeroTier messages are * nowhere near this large. */ -class Salsa20 : public TriviallyCopyable -{ -public: +class Salsa20 : public TriviallyCopyable { + public: #ifdef ZT_SALSA20_SSE - static constexpr bool accelerated() noexcept - { return true; } + static constexpr bool accelerated() noexcept + { + return true; + } #else - static constexpr bool accelerated() noexcept { return false; } + static constexpr bool accelerated() noexcept + { + return false; + } #endif - ZT_INLINE Salsa20() noexcept - {} + ZT_INLINE Salsa20() noexcept + { + } - ZT_INLINE ~Salsa20() noexcept - { Utils::burn(&_state, sizeof(_state)); } + ZT_INLINE ~Salsa20() noexcept + { + Utils::burn(&_state, sizeof(_state)); + } - /** - * @param key 256-bit (32 byte) key - * @param iv 64-bit initialization vector - */ - ZT_INLINE Salsa20(const void *key, const void *iv) noexcept - { init(key, iv); } + /** + * @param key 256-bit (32 byte) key + * @param iv 64-bit initialization vector + */ + ZT_INLINE Salsa20(const void* key, const void* iv) noexcept + { + init(key, iv); + } - /** - * Initialize cipher - * - * @param key Key bits - * @param iv 64-bit initialization vector - */ - void init(const void *key, const void *iv) noexcept; + /** + * Initialize cipher + * + * @param key Key bits + * @param iv 64-bit initialization vector + */ + void init(const void* key, const void* iv) noexcept; - /** - * Encrypt/decrypt data using Salsa20/12 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt12(const void *in, void *out, unsigned int bytes) noexcept; + /** + * Encrypt/decrypt data using Salsa20/12 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void crypt12(const void* in, void* out, unsigned int bytes) noexcept; - /** - * Encrypt/decrypt data using Salsa20/20 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt20(const void *in, void *out, unsigned int bytes) noexcept; + /** + * Encrypt/decrypt data using Salsa20/20 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void crypt20(const void* in, void* out, unsigned int bytes) noexcept; -private: - union - { + private: + union { #ifdef ZT_SALSA20_SSE - __m128i v[4]; -#endif // ZT_SALSA20_SSE - uint32_t i[16]; - } _state; + __m128i v[4]; +#endif // ZT_SALSA20_SSE + uint32_t i[16]; + } _state; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/ScopedPtr.hpp b/core/ScopedPtr.hpp index 6b7b67172..c79690890 100644 --- a/core/ScopedPtr.hpp +++ b/core/ScopedPtr.hpp @@ -24,66 +24,88 @@ namespace ZeroTier { * * This is used in the core to avoid requiring C++11 and because auto_ptr is weird. */ -template< typename T > -class ScopedPtr : public TriviallyCopyable -{ -public: - explicit ZT_INLINE ScopedPtr(T *const p) noexcept: m_ptr(p) - {} +template class ScopedPtr : public TriviallyCopyable { + public: + explicit ZT_INLINE ScopedPtr(T* const p) noexcept : m_ptr(p) + { + } - ZT_INLINE ~ScopedPtr() - { delete m_ptr; } + ZT_INLINE ~ScopedPtr() + { + delete m_ptr; + } - ZT_INLINE T *operator->() const noexcept - { return m_ptr; } + ZT_INLINE T* operator->() const noexcept + { + return m_ptr; + } - ZT_INLINE T &operator*() const noexcept - { return *m_ptr; } + ZT_INLINE T& operator*() const noexcept + { + return *m_ptr; + } - ZT_INLINE T *ptr() const noexcept - { return m_ptr; } + ZT_INLINE T* ptr() const noexcept + { + return m_ptr; + } - ZT_INLINE void swap(const ScopedPtr &p) noexcept - { - T *const tmp = m_ptr; - m_ptr = p.m_ptr; - p.m_ptr = tmp; - } + ZT_INLINE void swap(const ScopedPtr& p) noexcept + { + T* const tmp = m_ptr; + m_ptr = p.m_ptr; + p.m_ptr = tmp; + } - explicit ZT_INLINE operator bool() const noexcept - { return (m_ptr != (T *)0); } + explicit ZT_INLINE operator bool() const noexcept + { + return (m_ptr != (T*)0); + } - ZT_INLINE bool operator==(const ScopedPtr &p) const noexcept - { return (m_ptr == p.m_ptr); } + ZT_INLINE bool operator==(const ScopedPtr& p) const noexcept + { + return (m_ptr == p.m_ptr); + } - ZT_INLINE bool operator!=(const ScopedPtr &p) const noexcept - { return (m_ptr != p.m_ptr); } + ZT_INLINE bool operator!=(const ScopedPtr& p) const noexcept + { + return (m_ptr != p.m_ptr); + } - ZT_INLINE bool operator==(T *const p) const noexcept - { return (m_ptr == p); } + ZT_INLINE bool operator==(T* const p) const noexcept + { + return (m_ptr == p); + } - ZT_INLINE bool operator!=(T *const p) const noexcept - { return (m_ptr != p); } + ZT_INLINE bool operator!=(T* const p) const noexcept + { + return (m_ptr != p); + } -private: - ZT_INLINE ScopedPtr() noexcept - {} + private: + ZT_INLINE ScopedPtr() noexcept + { + } - ZT_INLINE ScopedPtr(const ScopedPtr &p) noexcept: m_ptr(nullptr) - {} + ZT_INLINE ScopedPtr(const ScopedPtr& p) noexcept : m_ptr(nullptr) + { + } - ZT_INLINE ScopedPtr &operator=(const ScopedPtr &p) noexcept - { return *this; } + ZT_INLINE ScopedPtr& operator=(const ScopedPtr& p) noexcept + { + return *this; + } - T *const m_ptr; + T* const m_ptr; }; -} // namespace ZeroTier +} // namespace ZeroTier namespace std { -template< typename T > -ZT_INLINE void swap(ZeroTier::ScopedPtr< T > &a, ZeroTier::ScopedPtr< T > &b) noexcept -{ a.swap(b); } -} // namespace std +template ZT_INLINE void swap(ZeroTier::ScopedPtr& a, ZeroTier::ScopedPtr& b) noexcept +{ + a.swap(b); +} +} // namespace std #endif diff --git a/core/SelfAwareness.cpp b/core/SelfAwareness.cpp index 9a42f23aa..3463f30c7 100644 --- a/core/SelfAwareness.cpp +++ b/core/SelfAwareness.cpp @@ -11,92 +11,112 @@ */ /****/ -#include "Constants.hpp" #include "SelfAwareness.hpp" -#include "Context.hpp" -#include "Topology.hpp" -#include "Peer.hpp" -#include "Trace.hpp" + +#include "Constants.hpp" #include "Containers.hpp" +#include "Context.hpp" +#include "Peer.hpp" +#include "Topology.hpp" +#include "Trace.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000 namespace ZeroTier { -SelfAwareness::SelfAwareness(const Context &ctx) : - m_ctx(ctx) -{} - -void SelfAwareness::iam(const CallContext &cc, const Identity &reporter, const int64_t receivedOnLocalSocket, const InetAddress &reporterPhysicalAddress, const InetAddress &myPhysicalAddress, bool trusted) +SelfAwareness::SelfAwareness(const Context& ctx) : m_ctx(ctx) { - const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); - - if ((scope != reporterPhysicalAddress.ipScope()) || (scope == ZT_IP_SCOPE_NONE) || (scope == ZT_IP_SCOPE_LOOPBACK) || (scope == ZT_IP_SCOPE_MULTICAST)) - return; - - Mutex::Lock l(m_phy_l); - p_PhySurfaceEntry &entry = m_phy[p_PhySurfaceKey(reporter.address(), receivedOnLocalSocket, reporterPhysicalAddress, scope)]; - - if ((trusted) && ((cc.ticks - entry.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress))) { - // Changes to external surface reported by trusted peers causes path reset in this scope - entry.mySurface = myPhysicalAddress; - entry.timestampTicks = cc.ticks; - entry.trusted = trusted; - - // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' - // due to multiple reports of endpoint change. - // Don't use 'entry' after this since hash table gets modified. - for (Map< p_PhySurfaceKey, p_PhySurfaceEntry >::iterator i(m_phy.begin()); i != m_phy.end();) { - if ((i->first.scope == scope) && (i->first.reporterPhysicalAddress != reporterPhysicalAddress)) - m_phy.erase(i++); - else ++i; - } - - // Reset all paths within this scope and address family - Vector< SharedPtr< Peer > > peers, rootPeers; - m_ctx.topology->allPeers(peers, rootPeers); - for(Vector< SharedPtr< Peer > >::const_iterator p(peers.begin());p!=peers.end();++p) - (*p)->resetWithinScope(m_ctx, cc, (InetAddress::IpScope)scope, myPhysicalAddress.as.sa.sa_family); - - m_ctx.t->resettingPathsInScope(cc, 0x9afff100, reporter, reporterPhysicalAddress, entry.mySurface, myPhysicalAddress, scope); - } else { - // Otherwise just update DB to use to determine external surface info - entry.mySurface = myPhysicalAddress; - entry.timestampTicks = cc.ticks; - entry.trusted = trusted; - } } -void SelfAwareness::clean(const CallContext &cc) +void SelfAwareness::iam( + const CallContext& cc, + const Identity& reporter, + const int64_t receivedOnLocalSocket, + const InetAddress& reporterPhysicalAddress, + const InetAddress& myPhysicalAddress, + bool trusted) { - Mutex::Lock l(m_phy_l); - for (Map< p_PhySurfaceKey, p_PhySurfaceEntry >::iterator i(m_phy.begin()); i != m_phy.end();) { - if ((cc.ticks - i->second.timestampTicks) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) - m_phy.erase(i++); - else ++i; - } + const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); + + if ((scope != reporterPhysicalAddress.ipScope()) || (scope == ZT_IP_SCOPE_NONE) || (scope == ZT_IP_SCOPE_LOOPBACK) + || (scope == ZT_IP_SCOPE_MULTICAST)) + return; + + Mutex::Lock l(m_phy_l); + p_PhySurfaceEntry& entry = + m_phy[p_PhySurfaceKey(reporter.address(), receivedOnLocalSocket, reporterPhysicalAddress, scope)]; + + if ((trusted) && ((cc.ticks - entry.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) + && (! entry.mySurface.ipsEqual(myPhysicalAddress))) { + // Changes to external surface reported by trusted peers causes path reset in this scope + entry.mySurface = myPhysicalAddress; + entry.timestampTicks = cc.ticks; + entry.trusted = trusted; + + // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' + // due to multiple reports of endpoint change. + // Don't use 'entry' after this since hash table gets modified. + for (Map::iterator i(m_phy.begin()); i != m_phy.end();) { + if ((i->first.scope == scope) && (i->first.reporterPhysicalAddress != reporterPhysicalAddress)) + m_phy.erase(i++); + else + ++i; + } + + // Reset all paths within this scope and address family + Vector > peers, rootPeers; + m_ctx.topology->allPeers(peers, rootPeers); + for (Vector >::const_iterator p(peers.begin()); p != peers.end(); ++p) + (*p)->resetWithinScope(m_ctx, cc, (InetAddress::IpScope)scope, myPhysicalAddress.as.sa.sa_family); + + m_ctx.t->resettingPathsInScope( + cc, + 0x9afff100, + reporter, + reporterPhysicalAddress, + entry.mySurface, + myPhysicalAddress, + scope); + } + else { + // Otherwise just update DB to use to determine external surface info + entry.mySurface = myPhysicalAddress; + entry.timestampTicks = cc.ticks; + entry.trusted = trusted; + } } -MultiMap< unsigned int, InetAddress > SelfAwareness::externalAddresses(CallContext &cc) const +void SelfAwareness::clean(const CallContext& cc) { - MultiMap< unsigned int, InetAddress > r; - - // Count endpoints reporting each IP/port combo - Map< InetAddress, unsigned long > counts; - { - Mutex::Lock l(m_phy_l); - for (Map< p_PhySurfaceKey, p_PhySurfaceEntry >::const_iterator i(m_phy.begin()); i != m_phy.end(); ++i) { - if ((cc.ticks - i->second.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) - ++counts[i->second.mySurface]; - } - } - - // Invert to create a map from count to address - for (Map< InetAddress, unsigned long >::iterator i(counts.begin()); i != counts.end(); ++i) - r.insert(std::pair< unsigned long, InetAddress >(i->second, i->first)); - - return r; + Mutex::Lock l(m_phy_l); + for (Map::iterator i(m_phy.begin()); i != m_phy.end();) { + if ((cc.ticks - i->second.timestampTicks) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) + m_phy.erase(i++); + else + ++i; + } } -} // namespace ZeroTier +MultiMap SelfAwareness::externalAddresses(CallContext& cc) const +{ + MultiMap r; + + // Count endpoints reporting each IP/port combo + Map counts; + { + Mutex::Lock l(m_phy_l); + for (Map::const_iterator i(m_phy.begin()); i != m_phy.end(); ++i) { + if ((cc.ticks - i->second.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) + ++counts[i->second.mySurface]; + } + } + + // Invert to create a map from count to address + for (Map::iterator i(counts.begin()); i != counts.end(); ++i) + r.insert(std::pair(i->second, i->first)); + + return r; +} + +} // namespace ZeroTier diff --git a/core/SelfAwareness.hpp b/core/SelfAwareness.hpp index 14f467728..0d87d0a37 100644 --- a/core/SelfAwareness.hpp +++ b/core/SelfAwareness.hpp @@ -14,12 +14,12 @@ #ifndef ZT_SELFAWARENESS_HPP #define ZT_SELFAWARENESS_HPP -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Containers.hpp" #include "Address.hpp" -#include "Mutex.hpp" #include "CallContext.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "InetAddress.hpp" +#include "Mutex.hpp" namespace ZeroTier { @@ -31,94 +31,123 @@ class Context; * * Name aside, it shouldn't be capable of achieving sentience. */ -class SelfAwareness -{ -public: - explicit SelfAwareness(const Context &ctx); +class SelfAwareness { + public: + explicit SelfAwareness(const Context& ctx); - /** - * Called when a remote peer informs us of our external network address - * - * @param reporter Identity of reporting peer - * @param receivedOnLocalAddress Local address on which report was received - * @param reporterPhysicalAddress Physical address that reporting peer seems to have - * @param myPhysicalAddress Physical address that peer says we have - * @param trusted True if this peer is trusted as an authority to inform us of external address changes - */ - void iam(const CallContext &cc, const Identity &reporter, int64_t receivedOnLocalSocket, const InetAddress &reporterPhysicalAddress, const InetAddress &myPhysicalAddress, bool trusted); + /** + * Called when a remote peer informs us of our external network address + * + * @param reporter Identity of reporting peer + * @param receivedOnLocalAddress Local address on which report was received + * @param reporterPhysicalAddress Physical address that reporting peer seems to have + * @param myPhysicalAddress Physical address that peer says we have + * @param trusted True if this peer is trusted as an authority to inform us of external address changes + */ + void + iam(const CallContext& cc, + const Identity& reporter, + int64_t receivedOnLocalSocket, + const InetAddress& reporterPhysicalAddress, + const InetAddress& myPhysicalAddress, + bool trusted); - /** - * Clean up database periodically - */ - void clean(const CallContext &cc); + /** + * Clean up database periodically + */ + void clean(const CallContext& cc); - /** - * Get external address consensus, which is the statistical "mode" of external addresses. - * - * @return Map of count to IP/port representing how many endpoints reported each address - */ - MultiMap< unsigned int, InetAddress > externalAddresses(CallContext &cc) const; + /** + * Get external address consensus, which is the statistical "mode" of external addresses. + * + * @return Map of count to IP/port representing how many endpoints reported each address + */ + MultiMap externalAddresses(CallContext& cc) const; -private: - struct p_PhySurfaceKey - { - Address reporter; - int64_t receivedOnLocalSocket; - InetAddress reporterPhysicalAddress; - InetAddress::IpScope scope; + private: + struct p_PhySurfaceKey { + Address reporter; + int64_t receivedOnLocalSocket; + InetAddress reporterPhysicalAddress; + InetAddress::IpScope scope; - ZT_INLINE p_PhySurfaceKey() noexcept - {} + ZT_INLINE p_PhySurfaceKey() noexcept + { + } - ZT_INLINE p_PhySurfaceKey(const Address &r, const int64_t rol, const InetAddress &ra, InetAddress::IpScope s) noexcept: reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s) - {} + ZT_INLINE + p_PhySurfaceKey(const Address& r, const int64_t rol, const InetAddress& ra, InetAddress::IpScope s) noexcept + : reporter(r) + , receivedOnLocalSocket(rol) + , reporterPhysicalAddress(ra) + , scope(s) + { + } - ZT_INLINE unsigned long hashCode() const noexcept - { return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); + } - ZT_INLINE bool operator==(const p_PhySurfaceKey &k) const noexcept - { return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); } + ZT_INLINE bool operator==(const p_PhySurfaceKey& k) const noexcept + { + return ( + (reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) + && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); + } - ZT_INLINE bool operator!=(const p_PhySurfaceKey &k) const noexcept - { return (!(*this == k)); } + ZT_INLINE bool operator!=(const p_PhySurfaceKey& k) const noexcept + { + return (! (*this == k)); + } - ZT_INLINE bool operator<(const p_PhySurfaceKey &k) const noexcept - { - if (reporter < k.reporter) { - return true; - } else if (reporter == k.reporter) { - if (receivedOnLocalSocket < k.receivedOnLocalSocket) { - return true; - } else if (receivedOnLocalSocket == k.receivedOnLocalSocket) { - if (reporterPhysicalAddress < k.reporterPhysicalAddress) { - return true; - } else if (reporterPhysicalAddress == k.reporterPhysicalAddress) { - return scope < k.scope; - } - } - } - return false; - } - }; + ZT_INLINE bool operator<(const p_PhySurfaceKey& k) const noexcept + { + if (reporter < k.reporter) { + return true; + } + else if (reporter == k.reporter) { + if (receivedOnLocalSocket < k.receivedOnLocalSocket) { + return true; + } + else if (receivedOnLocalSocket == k.receivedOnLocalSocket) { + if (reporterPhysicalAddress < k.reporterPhysicalAddress) { + return true; + } + else if (reporterPhysicalAddress == k.reporterPhysicalAddress) { + return scope < k.scope; + } + } + } + return false; + } + }; - struct p_PhySurfaceEntry - { - InetAddress mySurface; - int64_t timestampTicks; - bool trusted; + struct p_PhySurfaceEntry { + InetAddress mySurface; + int64_t timestampTicks; + bool trusted; - ZT_INLINE p_PhySurfaceEntry() noexcept: mySurface(), timestampTicks(0), trusted(false) - {} + ZT_INLINE p_PhySurfaceEntry() noexcept + : mySurface() + , timestampTicks(0) + , trusted(false) + { + } - ZT_INLINE p_PhySurfaceEntry(const InetAddress &a, const int64_t t) noexcept: mySurface(a), timestampTicks(t), trusted(false) - {} - }; + ZT_INLINE p_PhySurfaceEntry(const InetAddress& a, const int64_t t) noexcept + : mySurface(a) + , timestampTicks(t) + , trusted(false) + { + } + }; - const Context &m_ctx; - Map< p_PhySurfaceKey, p_PhySurfaceEntry > m_phy; - Mutex m_phy_l; + const Context& m_ctx; + Map m_phy; + Mutex m_phy_l; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/SharedPtr.hpp b/core/SharedPtr.hpp index 0ea2398df..a95800a37 100644 --- a/core/SharedPtr.hpp +++ b/core/SharedPtr.hpp @@ -25,173 +25,205 @@ namespace ZeroTier { * Classes must have an atomic field called __refCount and set this class * as a friend to be used with this. */ -template< typename T > -class SharedPtr : public TriviallyCopyable -{ -public: - ZT_INLINE SharedPtr() noexcept: m_ptr(nullptr) - {} +template class SharedPtr : public TriviallyCopyable { + public: + ZT_INLINE SharedPtr() noexcept : m_ptr(nullptr) + { + } - explicit ZT_INLINE SharedPtr(T *obj) noexcept: m_ptr(obj) - { if (likely(obj != nullptr)) const_cast *>(&(obj->__refCount))->fetch_add(1, std::memory_order_acquire); } + explicit ZT_INLINE SharedPtr(T* obj) noexcept : m_ptr(obj) + { + if (likely(obj != nullptr)) + const_cast*>(&(obj->__refCount))->fetch_add(1, std::memory_order_acquire); + } - ZT_INLINE SharedPtr(const SharedPtr &sp) noexcept: m_ptr(sp.m_acquire()) - {} + ZT_INLINE SharedPtr(const SharedPtr& sp) noexcept : m_ptr(sp.m_acquire()) + { + } - ZT_INLINE ~SharedPtr() - { m_release(); } + ZT_INLINE ~SharedPtr() + { + m_release(); + } - ZT_INLINE SharedPtr &operator=(const SharedPtr &sp) - { - if (likely(m_ptr != sp.m_ptr)) { - T *const p = sp.m_acquire(); - m_release(); - m_ptr = p; - } - return *this; - } + ZT_INLINE SharedPtr& operator=(const SharedPtr& sp) + { + if (likely(m_ptr != sp.m_ptr)) { + T* const p = sp.m_acquire(); + m_release(); + m_ptr = p; + } + return *this; + } - ZT_INLINE void set(T *ptr) noexcept - { - m_release(); - m_ptr = ptr; - const_cast *>(&(ptr->__refCount))->fetch_add(1, std::memory_order_acquire); - } + ZT_INLINE void set(T* ptr) noexcept + { + m_release(); + m_ptr = ptr; + const_cast*>(&(ptr->__refCount))->fetch_add(1, std::memory_order_acquire); + } - /** - * Swap with another pointer. - * - * This is much faster than using assignment as it requires no atomic - * operations at all. - * - * @param with Pointer to swap with - */ - ZT_INLINE void swap(SharedPtr &with) noexcept - { - T *const tmp = m_ptr; - m_ptr = with.m_ptr; - with.m_ptr = tmp; - } + /** + * Swap with another pointer. + * + * This is much faster than using assignment as it requires no atomic + * operations at all. + * + * @param with Pointer to swap with + */ + ZT_INLINE void swap(SharedPtr& with) noexcept + { + T* const tmp = m_ptr; + m_ptr = with.m_ptr; + with.m_ptr = tmp; + } - /** - * Move pointer from another SharedPtr to this one, zeroing target. - * - * This is faster than assignment as it saves one atomically synchronized - * increment. If this pointer is null there are no atomic operations at - * all. - * - * @param from Source pointer; will be changed to NULL - */ - ZT_INLINE void move(SharedPtr &from) - { - m_release(); - m_ptr = from.m_ptr; - from.m_ptr = nullptr; - } + /** + * Move pointer from another SharedPtr to this one, zeroing target. + * + * This is faster than assignment as it saves one atomically synchronized + * increment. If this pointer is null there are no atomic operations at + * all. + * + * @param from Source pointer; will be changed to NULL + */ + ZT_INLINE void move(SharedPtr& from) + { + m_release(); + m_ptr = from.m_ptr; + from.m_ptr = nullptr; + } - ZT_INLINE operator bool() const noexcept - { return (m_ptr != nullptr); } + ZT_INLINE operator bool() const noexcept + { + return (m_ptr != nullptr); + } - ZT_INLINE T &operator*() const noexcept - { return *m_ptr; } + ZT_INLINE T& operator*() const noexcept + { + return *m_ptr; + } - ZT_INLINE T *operator->() const noexcept - { return m_ptr; } + ZT_INLINE T* operator->() const noexcept + { + return m_ptr; + } - /** - * @return Raw pointer to held object - */ - ZT_INLINE T *ptr() const noexcept - { return m_ptr; } + /** + * @return Raw pointer to held object + */ + ZT_INLINE T* ptr() const noexcept + { + return m_ptr; + } - /** - * Set this pointer to NULL - */ - ZT_INLINE void zero() - { - m_release(); - m_ptr = nullptr; - } + /** + * Set this pointer to NULL + */ + ZT_INLINE void zero() + { + m_release(); + m_ptr = nullptr; + } - /** - * Return held object and null this pointer if reference count is one. - * - * If the reference count is one, the reference count is changed to zero - * and the object is returned. It is not deleted; the caller must do that - * if that is desired. This pointer will be set to NULL. If the reference - * count is not one nothing happens and NULL is returned. - * - * @return Pointer or NULL if more than one reference - */ - ZT_INLINE T *weakGC() - { - if (likely(m_ptr != nullptr)) { - int one = 1; - if (const_cast *>(&(m_ptr->__refCount))->compare_exchange_strong(one, (int)0)) { - T *const ptr = m_ptr; - m_ptr = nullptr; - return ptr; - } else { - return nullptr; - } - } else { - return nullptr; - } - } + /** + * Return held object and null this pointer if reference count is one. + * + * If the reference count is one, the reference count is changed to zero + * and the object is returned. It is not deleted; the caller must do that + * if that is desired. This pointer will be set to NULL. If the reference + * count is not one nothing happens and NULL is returned. + * + * @return Pointer or NULL if more than one reference + */ + ZT_INLINE T* weakGC() + { + if (likely(m_ptr != nullptr)) { + int one = 1; + if (const_cast*>(&(m_ptr->__refCount))->compare_exchange_strong(one, (int)0)) { + T* const ptr = m_ptr; + m_ptr = nullptr; + return ptr; + } + else { + return nullptr; + } + } + else { + return nullptr; + } + } - ZT_INLINE unsigned long hashCode() const noexcept - { return (unsigned long)((uintptr_t)m_ptr + (uintptr_t)Utils::hash32((uint32_t)m_ptr)); } + ZT_INLINE unsigned long hashCode() const noexcept + { + return (unsigned long)((uintptr_t)m_ptr + (uintptr_t)Utils::hash32((uint32_t)m_ptr)); + } - ZT_INLINE bool operator==(const SharedPtr &sp) const noexcept - { return (m_ptr == sp.m_ptr); } + ZT_INLINE bool operator==(const SharedPtr& sp) const noexcept + { + return (m_ptr == sp.m_ptr); + } - ZT_INLINE bool operator!=(const SharedPtr &sp) const noexcept - { return (m_ptr != sp.m_ptr); } + ZT_INLINE bool operator!=(const SharedPtr& sp) const noexcept + { + return (m_ptr != sp.m_ptr); + } - ZT_INLINE bool operator>(const SharedPtr &sp) const noexcept - { return (reinterpret_cast(m_ptr) > reinterpret_cast(sp.m_ptr)); } + ZT_INLINE bool operator>(const SharedPtr& sp) const noexcept + { + return (reinterpret_cast(m_ptr) > reinterpret_cast(sp.m_ptr)); + } - ZT_INLINE bool operator<(const SharedPtr &sp) const noexcept - { return (reinterpret_cast(m_ptr) < reinterpret_cast(sp.m_ptr)); } + ZT_INLINE bool operator<(const SharedPtr& sp) const noexcept + { + return (reinterpret_cast(m_ptr) < reinterpret_cast(sp.m_ptr)); + } - ZT_INLINE bool operator>=(const SharedPtr &sp) const noexcept - { return (reinterpret_cast(m_ptr) >= reinterpret_cast(sp.m_ptr)); } + ZT_INLINE bool operator>=(const SharedPtr& sp) const noexcept + { + return (reinterpret_cast(m_ptr) >= reinterpret_cast(sp.m_ptr)); + } - ZT_INLINE bool operator<=(const SharedPtr &sp) const noexcept - { return (reinterpret_cast(m_ptr) <= reinterpret_cast(sp.m_ptr)); } + ZT_INLINE bool operator<=(const SharedPtr& sp) const noexcept + { + return (reinterpret_cast(m_ptr) <= reinterpret_cast(sp.m_ptr)); + } -private: - ZT_INLINE T *m_acquire() const noexcept - { - if (likely(m_ptr != nullptr)) - const_cast *>(&(m_ptr->__refCount))->fetch_add(1, std::memory_order_acquire); - return m_ptr; - } + private: + ZT_INLINE T* m_acquire() const noexcept + { + if (likely(m_ptr != nullptr)) + const_cast*>(&(m_ptr->__refCount))->fetch_add(1, std::memory_order_acquire); + return m_ptr; + } - ZT_INLINE void m_release() const noexcept - { - if (likely(m_ptr != nullptr)) { - if (unlikely(const_cast *>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1)) - delete m_ptr; - } - } + ZT_INLINE void m_release() const noexcept + { + if (likely(m_ptr != nullptr)) { + if (unlikely( + const_cast*>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1)) + delete m_ptr; + } + } - T *m_ptr; + T* m_ptr; }; -} // namespace ZeroTier +} // namespace ZeroTier // Augment std::swap to speed up some operations with SharedPtr. namespace std { -template< typename T > -ZT_MAYBE_UNUSED ZT_INLINE void swap(ZeroTier::SharedPtr< T > &a, ZeroTier::SharedPtr< T > &b) noexcept -{ a.swap(b); } +template ZT_MAYBE_UNUSED ZT_INLINE void swap(ZeroTier::SharedPtr& a, ZeroTier::SharedPtr& b) noexcept +{ + a.swap(b); +} -template< typename T > -ZT_MAYBE_UNUSED ZT_INLINE void move(ZeroTier::SharedPtr< T > &a, ZeroTier::SharedPtr< T > &b) noexcept -{ a.move(b); } +template ZT_MAYBE_UNUSED ZT_INLINE void move(ZeroTier::SharedPtr& a, ZeroTier::SharedPtr& b) noexcept +{ + a.move(b); +} -} // namespace std +} // namespace std #endif diff --git a/core/Spinlock.hpp b/core/Spinlock.hpp index 5b78366f8..10082825c 100644 --- a/core/Spinlock.hpp +++ b/core/Spinlock.hpp @@ -29,47 +29,54 @@ * This can be used in place of Mutex to lock things that are extremely fast * to access. It should be used very sparingly. */ -class Spinlock -{ -public: - /** - * Pause current thread using whatever methods might be available - * - * This is broken out since it's used in a few other places where - * spinlock-like constructions are used. - */ - ZT_INLINE static void pause() noexcept - { +class Spinlock { + public: + /** + * Pause current thread using whatever methods might be available + * + * This is broken out since it's used in a few other places where + * spinlock-like constructions are used. + */ + ZT_INLINE static void pause() noexcept + { #ifdef ZT_ARCH_X64 - _mm_pause(); + _mm_pause(); #endif #ifdef __LINUX__ - sched_yield(); + sched_yield(); #else - std::this_thread::yield(); + std::this_thread::yield(); #endif - } + } - ZT_INLINE Spinlock() noexcept: m_locked(false) - {} + ZT_INLINE Spinlock() noexcept : m_locked(false) + { + } - ZT_INLINE void lock() noexcept - { - if (unlikely(m_locked.test_and_set(std::memory_order_acquire))) { - do { - Spinlock::pause(); - } while (m_locked.test_and_set(std::memory_order_acquire)); - } - } + ZT_INLINE void lock() noexcept + { + if (unlikely(m_locked.test_and_set(std::memory_order_acquire))) { + do { + Spinlock::pause(); + } while (m_locked.test_and_set(std::memory_order_acquire)); + } + } - ZT_INLINE void unlock() noexcept - { m_locked.clear(std::memory_order_release); } + ZT_INLINE void unlock() noexcept + { + m_locked.clear(std::memory_order_release); + } -private: - ZT_INLINE Spinlock(const Spinlock &) noexcept {} - ZT_INLINE const Spinlock &operator=(const Spinlock &) noexcept { return *this; } + private: + ZT_INLINE Spinlock(const Spinlock&) noexcept + { + } + ZT_INLINE const Spinlock& operator=(const Spinlock&) noexcept + { + return *this; + } - std::atomic_flag m_locked; + std::atomic_flag m_locked; }; #endif diff --git a/core/Store.hpp b/core/Store.hpp index 3a5b022d6..ddcae8356 100644 --- a/core/Store.hpp +++ b/core/Store.hpp @@ -14,69 +14,90 @@ #ifndef ZT_STORE_HPP #define ZT_STORE_HPP +#include "CallContext.hpp" #include "Constants.hpp" #include "Containers.hpp" #include "Context.hpp" -#include "CallContext.hpp" namespace ZeroTier { /** * Wrapper around API callbacks for data store */ -class Store -{ -public: - ZT_INLINE Store(const Context &ctx): m_ctx(ctx) - {} +class Store { + public: + ZT_INLINE Store(const Context& ctx) : m_ctx(ctx) + { + } - /** - * Get a state object - * - * @param type Object type - * @param id Object ID - * @param idSize Size of object ID in qwords - * @return Data or empty vector if not found - */ - ZT_INLINE Vector< uint8_t > get(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, unsigned int idSize) const - { - Vector< uint8_t > dv; - void *data = nullptr; - void (*freeFunc)(void *) = nullptr; - const int r = m_ctx.cb.stateGetFunction(reinterpret_cast(m_ctx.node), m_ctx.uPtr, cc.tPtr, type, id, idSize, &data, &freeFunc); - if (r > 0) - dv.assign(reinterpret_cast(data), reinterpret_cast(data) + r); - if ((data) && (freeFunc)) - freeFunc(data); - return dv; - } + /** + * Get a state object + * + * @param type Object type + * @param id Object ID + * @param idSize Size of object ID in qwords + * @return Data or empty vector if not found + */ + ZT_INLINE Vector + get(const CallContext& cc, ZT_StateObjectType type, const uint64_t* const id, unsigned int idSize) const + { + Vector dv; + void* data = nullptr; + void (*freeFunc)(void*) = nullptr; + const int r = m_ctx.cb.stateGetFunction( + reinterpret_cast(m_ctx.node), + m_ctx.uPtr, + cc.tPtr, + type, + id, + idSize, + &data, + &freeFunc); + if (r > 0) + dv.assign(reinterpret_cast(data), reinterpret_cast(data) + r); + if ((data) && (freeFunc)) + freeFunc(data); + return dv; + } - /** - * Store a state object - * - * @param type Object type - * @param id Object ID - * @param idSize Size of object ID in qwords - * @param data Data to store - * @param len Length of data - */ - ZT_INLINE void put(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize, const void *const data, const unsigned int len) noexcept - { m_ctx.cb.statePutFunction(reinterpret_cast(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, data, (int)len); } + /** + * Store a state object + * + * @param type Object type + * @param id Object ID + * @param idSize Size of object ID in qwords + * @param data Data to store + * @param len Length of data + */ + ZT_INLINE void + put(const CallContext& cc, + ZT_StateObjectType type, + const uint64_t* const id, + const unsigned int idSize, + const void* const data, + const unsigned int len) noexcept + { + m_ctx.cb + .statePutFunction(reinterpret_cast(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, data, (int)len); + } - /** - * Erase a state object from the object store - * - * @param type Object type - * @param id Object ID - * @param idSize Size of object ID in qwords - */ - ZT_INLINE void erase(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize) noexcept - { m_ctx.cb.statePutFunction(reinterpret_cast(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, nullptr, -1); } + /** + * Erase a state object from the object store + * + * @param type Object type + * @param id Object ID + * @param idSize Size of object ID in qwords + */ + ZT_INLINE void + erase(const CallContext& cc, ZT_StateObjectType type, const uint64_t* const id, const unsigned int idSize) noexcept + { + m_ctx.cb.statePutFunction(reinterpret_cast(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, nullptr, -1); + } -private: - const Context &m_ctx; + private: + const Context& m_ctx; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/SymmetricKey.hpp b/core/SymmetricKey.hpp index 63393bfdb..36f78795b 100644 --- a/core/SymmetricKey.hpp +++ b/core/SymmetricKey.hpp @@ -14,130 +14,139 @@ #ifndef ZT_SYMMETRICKEY_HPP #define ZT_SYMMETRICKEY_HPP -#include "Constants.hpp" -#include "Utils.hpp" #include "AES.hpp" #include "Address.hpp" +#include "Constants.hpp" +#include "Utils.hpp" namespace ZeroTier { /** * Container for symmetric keys and ciphers initialized with them. */ -class SymmetricKey -{ -public: - /** - * Construct an uninitialized key (init() must be called) - */ - ZT_INLINE SymmetricKey(): - m_secret(), - m_ts(-1), - m_initialNonce(0), - m_cipher(), - m_nonce(0) - {} +class SymmetricKey { + public: + /** + * Construct an uninitialized key (init() must be called) + */ + ZT_INLINE SymmetricKey() : m_secret(), m_ts(-1), m_initialNonce(0), m_cipher(), m_nonce(0) + { + } - /** - * Construct a new symmetric key - * - * SECURITY: the MSB of the nonce is always 0 because this bit is set to 0 - * or 1 depending on which "direction" data is moving. See nextMessage(). - * - * @param ts Key timestamp - * @param key Key (must be 48 bytes / 384 bits) - */ - ZT_INLINE SymmetricKey(const int64_t ts, const void *const key) noexcept: - m_secret(key), - m_ts(ts), - m_initialNonce(Utils::getSecureRandomU64() >> 1U), - m_cipher(key), - m_nonce(m_initialNonce) - {} + /** + * Construct a new symmetric key + * + * SECURITY: the MSB of the nonce is always 0 because this bit is set to 0 + * or 1 depending on which "direction" data is moving. See nextMessage(). + * + * @param ts Key timestamp + * @param key Key (must be 48 bytes / 384 bits) + */ + ZT_INLINE SymmetricKey(const int64_t ts, const void* const key) noexcept + : m_secret(key) + , m_ts(ts) + , m_initialNonce(Utils::getSecureRandomU64() >> 1U) + , m_cipher(key) + , m_nonce(m_initialNonce) + { + } - ZT_INLINE SymmetricKey(const SymmetricKey &k) noexcept: - m_secret(k.m_secret), - m_ts(k.m_ts), - m_initialNonce(k.m_initialNonce), - m_cipher(k.m_secret.data), - m_nonce(k.m_nonce.load(std::memory_order_relaxed)) - {} + ZT_INLINE SymmetricKey(const SymmetricKey& k) noexcept + : m_secret(k.m_secret) + , m_ts(k.m_ts) + , m_initialNonce(k.m_initialNonce) + , m_cipher(k.m_secret.data) + , m_nonce(k.m_nonce.load(std::memory_order_relaxed)) + { + } - ZT_INLINE ~SymmetricKey() noexcept - { Utils::burn(m_secret.data, ZT_SYMMETRIC_KEY_SIZE); } + ZT_INLINE ~SymmetricKey() noexcept + { + Utils::burn(m_secret.data, ZT_SYMMETRIC_KEY_SIZE); + } - ZT_INLINE SymmetricKey &operator=(const SymmetricKey &k) noexcept - { - m_secret = k.m_secret; - m_ts = k.m_ts; - m_initialNonce = k.m_initialNonce; - m_cipher.init(k.m_secret.data); - m_nonce.store(k.m_nonce.load(std::memory_order_relaxed), std::memory_order_relaxed); - return *this; - } + ZT_INLINE SymmetricKey& operator=(const SymmetricKey& k) noexcept + { + m_secret = k.m_secret; + m_ts = k.m_ts; + m_initialNonce = k.m_initialNonce; + m_cipher.init(k.m_secret.data); + m_nonce.store(k.m_nonce.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } - /** - * Initialize or re-initialize a symmetric key - * - * @param ts Key timestamp - * @param key Key (must be 48 bytes / 384 bits) - */ - ZT_INLINE void init(const int64_t ts, const void *const key) noexcept - { - Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(m_secret.data, key); - m_ts = ts; - m_initialNonce = Utils::getSecureRandomU64() >> 1U; - m_cipher.init(key); - m_nonce.store(m_initialNonce, std::memory_order_relaxed); - } + /** + * Initialize or re-initialize a symmetric key + * + * @param ts Key timestamp + * @param key Key (must be 48 bytes / 384 bits) + */ + ZT_INLINE void init(const int64_t ts, const void* const key) noexcept + { + Utils::copy(m_secret.data, key); + m_ts = ts; + m_initialNonce = Utils::getSecureRandomU64() >> 1U; + m_cipher.init(key); + m_nonce.store(m_initialNonce, std::memory_order_relaxed); + } - /** - * Advance usage counter by one and return the next IV / packet ID. - * - * @param sender Sending ZeroTier address - * @param receiver Receiving ZeroTier address - * @return Next unique IV for next message - */ - ZT_INLINE uint64_t nextMessage(const Address sender, const Address receiver) noexcept - { return m_nonce.fetch_add(1, std::memory_order_relaxed) ^ (((uint64_t)(sender > receiver)) << 63U); } + /** + * Advance usage counter by one and return the next IV / packet ID. + * + * @param sender Sending ZeroTier address + * @param receiver Receiving ZeroTier address + * @return Next unique IV for next message + */ + ZT_INLINE uint64_t nextMessage(const Address sender, const Address receiver) noexcept + { + return m_nonce.fetch_add(1, std::memory_order_relaxed) ^ (((uint64_t)(sender > receiver)) << 63U); + } - /** - * Get the number of times this key has been used. - * - * This is used along with the key's initial timestamp to determine key age - * for ephemeral key rotation. - * - * @return Number of times nextMessage() has been called since object creation - */ - ZT_INLINE uint64_t odometer() const noexcept - { return m_nonce.load(std::memory_order_relaxed) - m_initialNonce; } + /** + * Get the number of times this key has been used. + * + * This is used along with the key's initial timestamp to determine key age + * for ephemeral key rotation. + * + * @return Number of times nextMessage() has been called since object creation + */ + ZT_INLINE uint64_t odometer() const noexcept + { + return m_nonce.load(std::memory_order_relaxed) - m_initialNonce; + } - /** - * @return Key creation timestamp or -1 if this is a long-lived key - */ - ZT_INLINE int64_t timestamp() const noexcept - { return m_ts; } + /** + * @return Key creation timestamp or -1 if this is a long-lived key + */ + ZT_INLINE int64_t timestamp() const noexcept + { + return m_ts; + } - /** - * @return 48-byte / 384-bit secret key - */ - ZT_INLINE const uint8_t *key() const noexcept - { return m_secret.data; } + /** + * @return 48-byte / 384-bit secret key + */ + ZT_INLINE const uint8_t* key() const noexcept + { + return m_secret.data; + } - /** - * @return AES cipher (already initialized with secret key) - */ - ZT_INLINE const AES &aes() const noexcept - { return m_cipher; } + /** + * @return AES cipher (already initialized with secret key) + */ + ZT_INLINE const AES& aes() const noexcept + { + return m_cipher; + } -private: - Blob< ZT_SYMMETRIC_KEY_SIZE > m_secret; - int64_t m_ts; - uint64_t m_initialNonce; - AES m_cipher; - std::atomic< uint64_t > m_nonce; + private: + Blob m_secret; + int64_t m_ts; + uint64_t m_initialNonce; + AES m_cipher; + std::atomic m_nonce; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/TagCredential.cpp b/core/TagCredential.cpp index 3665983f6..ae898a851 100644 --- a/core/TagCredential.cpp +++ b/core/TagCredential.cpp @@ -15,71 +15,71 @@ namespace ZeroTier { -bool TagCredential::sign(const Identity &signer) noexcept +bool TagCredential::sign(const Identity& signer) noexcept { - uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX]; - if (signer.hasPrivate()) { - m_signedBy = signer.address(); - m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); - return true; - } - return false; + uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX]; + if (signer.hasPrivate()) { + m_signedBy = signer.address(); + m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature)); + return true; + } + return false; } int TagCredential::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noexcept { - int p = 0; - if (forSign) { - for (int k = 0; k < 8; ++k) - data[p++] = 0x7f; - } - Utils::storeBigEndian< uint64_t >(data + p, m_networkId); - Utils::storeBigEndian< uint64_t >(data + p + 8, (uint64_t)m_ts); - Utils::storeBigEndian< uint32_t >(data + p + 16, m_id); - Utils::storeBigEndian< uint32_t >(data + p + 20, m_value); - p += 24; - m_issuedTo.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - m_signedBy.copyTo(data + p); - p += ZT_ADDRESS_LENGTH; - if (!forSign) { - data[p++] = 1; - Utils::storeBigEndian< uint16_t >(data + p, (uint16_t)m_signatureLength); - p += 2; - Utils::copy(data + p, m_signature, m_signatureLength); - p += (int)m_signatureLength; - } - data[p++] = 0; - data[p++] = 0; - if (forSign) { - for (int k = 0; k < 8; ++k) - data[p++] = 0x7f; - } - return p; + int p = 0; + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } + Utils::storeBigEndian(data + p, m_networkId); + Utils::storeBigEndian(data + p + 8, (uint64_t)m_ts); + Utils::storeBigEndian(data + p + 16, m_id); + Utils::storeBigEndian(data + p + 20, m_value); + p += 24; + m_issuedTo.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + m_signedBy.copyTo(data + p); + p += ZT_ADDRESS_LENGTH; + if (! forSign) { + data[p++] = 1; + Utils::storeBigEndian(data + p, (uint16_t)m_signatureLength); + p += 2; + Utils::copy(data + p, m_signature, m_signatureLength); + p += (int)m_signatureLength; + } + data[p++] = 0; + data[p++] = 0; + if (forSign) { + for (int k = 0; k < 8; ++k) + data[p++] = 0x7f; + } + return p; } -int TagCredential::unmarshal(const uint8_t *data, int len) noexcept +int TagCredential::unmarshal(const uint8_t* data, int len) noexcept { - if (len < 37) - return -1; - m_networkId = Utils::loadBigEndian< uint64_t >(data); - m_ts = (int64_t)Utils::loadBigEndian< uint64_t >(data + 8); - m_id = Utils::loadBigEndian< uint32_t >(data + 16); - m_value = Utils::loadBigEndian< uint32_t >(data + 20); - m_issuedTo.setTo(data + 24); - m_signedBy.setTo(data + 29); - // 1 byte reserved - m_signatureLength = Utils::loadBigEndian< uint16_t >(data + 35); - int p = 37 + (int)m_signatureLength; - if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) - return -1; - Utils::copy(m_signature, data + p, m_signatureLength); - if ((p + 2) > len) - return -1; - p += 2 + Utils::loadBigEndian< uint16_t >(data + p); - if (p > len) - return -1; - return p; + if (len < 37) + return -1; + m_networkId = Utils::loadBigEndian(data); + m_ts = (int64_t)Utils::loadBigEndian(data + 8); + m_id = Utils::loadBigEndian(data + 16); + m_value = Utils::loadBigEndian(data + 20); + m_issuedTo.setTo(data + 24); + m_signedBy.setTo(data + 29); + // 1 byte reserved + m_signatureLength = Utils::loadBigEndian(data + 35); + int p = 37 + (int)m_signatureLength; + if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) + return -1; + Utils::copy(m_signature, data + p, m_signatureLength); + if ((p + 2) > len) + return -1; + p += 2 + Utils::loadBigEndian(data + p); + if (p > len) + return -1; + return p; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/TagCredential.hpp b/core/TagCredential.hpp index 60c5a04aa..9d6256132 100644 --- a/core/TagCredential.hpp +++ b/core/TagCredential.hpp @@ -14,10 +14,10 @@ #ifndef ZT_TAG_HPP #define ZT_TAG_HPP +#include "Address.hpp" +#include "C25519.hpp" #include "Constants.hpp" #include "Credential.hpp" -#include "C25519.hpp" -#include "Address.hpp" #include "Identity.hpp" #define ZT_TAG_MARSHAL_SIZE_MAX (8 + 8 + 4 + 4 + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) @@ -43,137 +43,191 @@ class Context; * Unlike capabilities tags are signed only by the issuer and are never * transferable. */ -class TagCredential : public Credential -{ - friend class Credential; +class TagCredential : public Credential { + friend class Credential; -public: - static constexpr ZT_CredentialType credentialType() noexcept - { return ZT_CREDENTIAL_TYPE_TAG; } + public: + static constexpr ZT_CredentialType credentialType() noexcept + { + return ZT_CREDENTIAL_TYPE_TAG; + } - ZT_INLINE TagCredential() noexcept - { memoryZero(this); } + ZT_INLINE TagCredential() noexcept + { + memoryZero(this); + } - /** - * @param nwid Network ID - * @param ts Timestamp - * @param issuedTo Address to which this tag was issued - * @param id Tag ID - * @param value Tag value - */ - ZT_INLINE TagCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id, const uint32_t value) noexcept: - m_id(id), - m_value(value), - m_networkId(nwid), - m_ts(ts), - m_issuedTo(issuedTo), - m_signedBy(), - m_signatureLength(0) - {} + /** + * @param nwid Network ID + * @param ts Timestamp + * @param issuedTo Address to which this tag was issued + * @param id Tag ID + * @param value Tag value + */ + ZT_INLINE TagCredential( + const uint64_t nwid, + const int64_t ts, + const Address& issuedTo, + const uint32_t id, + const uint32_t value) noexcept + : m_id(id) + , m_value(value) + , m_networkId(nwid) + , m_ts(ts) + , m_issuedTo(issuedTo) + , m_signedBy() + , m_signatureLength(0) + { + } - ZT_INLINE uint32_t id() const noexcept - { return m_id; } + ZT_INLINE uint32_t id() const noexcept + { + return m_id; + } - ZT_INLINE const uint32_t &value() const noexcept - { return m_value; } + ZT_INLINE const uint32_t& value() const noexcept + { + return m_value; + } - ZT_INLINE uint64_t networkId() const noexcept - { return m_networkId; } + ZT_INLINE uint64_t networkId() const noexcept + { + return m_networkId; + } - ZT_INLINE int64_t timestamp() const noexcept - { return m_ts; } + ZT_INLINE int64_t timestamp() const noexcept + { + return m_ts; + } - ZT_INLINE int64_t revision() const noexcept - { return m_ts; } + ZT_INLINE int64_t revision() const noexcept + { + return m_ts; + } - ZT_INLINE const Address &issuedTo() const noexcept - { return m_issuedTo; } + ZT_INLINE const Address& issuedTo() const noexcept + { + return m_issuedTo; + } - ZT_INLINE const Address &signer() const noexcept - { return m_signedBy; } + ZT_INLINE const Address& signer() const noexcept + { + return m_signedBy; + } - ZT_INLINE const uint8_t *signature() const noexcept - { return m_signature; } + ZT_INLINE const uint8_t* signature() const noexcept + { + return m_signature; + } - ZT_INLINE unsigned int signatureLength() const noexcept - { return m_signatureLength; } + ZT_INLINE unsigned int signatureLength() const noexcept + { + return m_signatureLength; + } - /** - * Sign this tag - * - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - bool sign(const Identity &signer) noexcept; + /** + * Sign this tag + * + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + bool sign(const Identity& signer) noexcept; - /** - * Check this tag's signature - * - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept - { return s_verify(ctx, cc, *this); } + /** + * Check this tag's signature + * + * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept + { + return s_verify(ctx, cc, *this); + } - static constexpr int marshalSizeMax() noexcept - { return ZT_TAG_MARSHAL_SIZE_MAX; } + static constexpr int marshalSizeMax() noexcept + { + return ZT_TAG_MARSHAL_SIZE_MAX; + } - int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; + int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; + int unmarshal(const uint8_t* data, int len) noexcept; - // Provides natural sort order by ID - ZT_INLINE bool operator<(const TagCredential &t) const noexcept - { return (m_id < t.m_id); } + // Provides natural sort order by ID + ZT_INLINE bool operator<(const TagCredential& t) const noexcept + { + return (m_id < t.m_id); + } - ZT_INLINE bool operator==(const TagCredential &t) const noexcept - { return (memcmp(this, &t, sizeof(TagCredential)) == 0); } + ZT_INLINE bool operator==(const TagCredential& t) const noexcept + { + return (memcmp(this, &t, sizeof(TagCredential)) == 0); + } - ZT_INLINE bool operator!=(const TagCredential &t) const noexcept - { return (memcmp(this, &t, sizeof(TagCredential)) != 0); } + ZT_INLINE bool operator!=(const TagCredential& t) const noexcept + { + return (memcmp(this, &t, sizeof(TagCredential)) != 0); + } - // For searching sorted arrays or lists of Tags by ID - struct IdComparePredicate - { - ZT_INLINE bool operator()(const TagCredential &a, const TagCredential &b) const noexcept - { return (a.id() < b.id()); } + // For searching sorted arrays or lists of Tags by ID + struct IdComparePredicate { + ZT_INLINE bool operator()(const TagCredential& a, const TagCredential& b) const noexcept + { + return (a.id() < b.id()); + } - ZT_INLINE bool operator()(const uint32_t a, const TagCredential &b) const noexcept - { return (a < b.id()); } + ZT_INLINE bool operator()(const uint32_t a, const TagCredential& b) const noexcept + { + return (a < b.id()); + } - ZT_INLINE bool operator()(const TagCredential &a, const uint32_t b) const noexcept - { return (a.id() < b); } + ZT_INLINE bool operator()(const TagCredential& a, const uint32_t b) const noexcept + { + return (a.id() < b); + } - ZT_INLINE bool operator()(const TagCredential *a, const TagCredential *b) const noexcept - { return (a->id() < b->id()); } + ZT_INLINE bool operator()(const TagCredential* a, const TagCredential* b) const noexcept + { + return (a->id() < b->id()); + } - ZT_INLINE bool operator()(const TagCredential *a, const TagCredential &b) const noexcept - { return (a->id() < b.id()); } + ZT_INLINE bool operator()(const TagCredential* a, const TagCredential& b) const noexcept + { + return (a->id() < b.id()); + } - ZT_INLINE bool operator()(const TagCredential &a, const TagCredential *b) const noexcept - { return (a.id() < b->id()); } + ZT_INLINE bool operator()(const TagCredential& a, const TagCredential* b) const noexcept + { + return (a.id() < b->id()); + } - ZT_INLINE bool operator()(const uint32_t a, const TagCredential *b) const noexcept - { return (a < b->id()); } + ZT_INLINE bool operator()(const uint32_t a, const TagCredential* b) const noexcept + { + return (a < b->id()); + } - ZT_INLINE bool operator()(const TagCredential *a, const uint32_t b) const noexcept - { return (a->id() < b); } + ZT_INLINE bool operator()(const TagCredential* a, const uint32_t b) const noexcept + { + return (a->id() < b); + } - ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept - { return (a < b); } - }; + ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept + { + return (a < b); + } + }; -private: - uint32_t m_id; - uint32_t m_value; - uint64_t m_networkId; - int64_t m_ts; - Address m_issuedTo; - Address m_signedBy; - unsigned int m_signatureLength; - uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; + private: + uint32_t m_id; + uint32_t m_value; + uint64_t m_networkId; + int64_t m_ts; + Address m_issuedTo; + Address m_signedBy; + unsigned int m_signatureLength; + uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Tests.cpp b/core/Tests.cpp index 122353bc8..e440d75f0 100644 --- a/core/Tests.cpp +++ b/core/Tests.cpp @@ -16,60 +16,58 @@ //#define ZT_ENABLE_TESTS #ifdef ZT_ENABLE_TESTS -#include "Constants.hpp" -#include "C25519.hpp" -#include "ECC384.hpp" #include "AES.hpp" -#include "Salsa20.hpp" -#include "Identity.hpp" -#include "Protocol.hpp" -#include "Dictionary.hpp" -#include "Utils.hpp" #include "Buf.hpp" -#include "InetAddress.hpp" -#include "Endpoint.hpp" -#include "Locator.hpp" -#include "MembershipCredential.hpp" -#include "OwnershipCredential.hpp" -#include "RevocationCredential.hpp" -#include "TagCredential.hpp" +#include "C25519.hpp" #include "CapabilityCredential.hpp" -#include "NetworkConfig.hpp" -#include "FCV.hpp" -#include "SHA512.hpp" -#include "Defragmenter.hpp" -#include "Fingerprint.hpp" -#include "Containers.hpp" -#include "Endpoint.hpp" -#include "Locator.hpp" #include "Certificate.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Defragmenter.hpp" +#include "Dictionary.hpp" +#include "ECC384.hpp" +#include "Endpoint.hpp" +#include "FCV.hpp" +#include "Fingerprint.hpp" +#include "Identity.hpp" +#include "InetAddress.hpp" +#include "Locator.hpp" #include "MIMC52.hpp" +#include "MembershipCredential.hpp" +#include "NetworkConfig.hpp" +#include "OwnershipCredential.hpp" +#include "Protocol.hpp" +#include "RevocationCredential.hpp" +#include "SHA512.hpp" +#include "Salsa20.hpp" #include "ScopedPtr.hpp" +#include "TagCredential.hpp" +#include "Utils.hpp" #ifdef __UNIX_LIKE__ -#include #include #include +#include #endif #ifdef __APPLE__ -#include #include +#include #include static clock_serv_t _machGetRealtimeClock() noexcept { - clock_serv_t c; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &c); - return c; + clock_serv_t c; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &c); + return c; } static clock_serv_t s_machRealtimeClock = _machGetRealtimeClock(); -#endif // __APPLE__ +#endif // __APPLE__ using namespace ZeroTier; @@ -78,27 +76,27 @@ static volatile unsigned int foo = 0; static int64_t now() { #ifdef __WINDOWS__ - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return (((LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32)) / 10000LL) - 116444736000000000LL; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return (((LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32)) / 10000LL) - 116444736000000000LL; #else #ifdef __LINUX__ - timespec ts; + timespec ts; #ifdef CLOCK_REALTIME_COARSE - clock_gettime(CLOCK_REALTIME_COARSE,&ts); + clock_gettime(CLOCK_REALTIME_COARSE, &ts); #else - clock_gettime(CLOCK_REALTIME,&ts); + clock_gettime(CLOCK_REALTIME, &ts); #endif - return ( (1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000)) ); + return ((1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000))); #else #ifdef __APPLE__ - mach_timespec_t mts; - clock_get_time(s_machRealtimeClock, &mts); - return ((1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000))); + mach_timespec_t mts; + clock_get_time(s_machRealtimeClock, &mts); + return ((1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000))); #else - timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); + timeval tv; + gettimeofday(&tv, (struct timezone*)0); + return ((1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000)); #endif #endif #endif @@ -106,121 +104,1271 @@ static int64_t now() // Cryptographic tests vectors ---------------------------------------------------------------------------------------- -static const uint8_t ECC384_TV0_PUBLIC[49] = {0x02, 0xed, 0xbc, 0xbb, 0x1f, 0x23, 0x9b, 0xbd, 0x9d, 0x3d, 0x7c, 0xef, 0x6b, 0x37, 0xa3, 0x26, 0x69, 0xe9, 0x4d, 0xf4, 0x26, 0x64, 0xfb, 0xac, 0x76, 0x40, 0xc2, 0x22, 0x21, 0xa6, 0xa3, 0xdf, 0x8c, 0x96, 0x81, 0x76, 0x0f, 0x0e, 0x67, 0xab, 0xd4, 0x51, 0x58, 0xb3, 0x15, 0x63, 0xfb, 0x49, 0x71}; -static const uint8_t ECC384_TV0_PRIVATE[48] = {0x62, 0x93, 0x9b, 0x4a, 0x29, 0x3c, 0xc6, 0x86, 0x98, 0xc3, 0xd0, 0x7f, 0xb7, 0xff, 0x97, 0xa2, 0xfb, 0xc9, 0x36, 0x8a, 0x1d, 0xa5, 0x40, 0x8e, 0x49, 0x13, 0xd4, 0x15, 0x46, 0xcb, 0xb4, 0x08, 0xfa, 0x8c, 0xb2, 0x7f, 0xcc, 0x3f, 0x72, 0xf8, 0x0d, 0x16, 0x7b, 0xf0, 0xa4, 0xc3, 0x29, 0xd3}; -static const uint8_t ECC384_TV0_DH_SELF_AGREE[48] = {0xf6, 0x96, 0xbd, 0x1b, 0xda, 0x5e, 0x52, 0x8c, 0x1d, 0x56, 0xa3, 0x6e, 0xd9, 0xba, 0xd7, 0x84, 0xdd, 0x20, 0x1b, 0x50, 0xc9, 0xd8, 0x68, 0xb9, 0x52, 0x93, 0x27, 0xab, 0x17, 0xed, 0xc6, 0xae, 0x89, 0x5e, 0x7f, 0xd9, 0x46, 0x15, 0x87, 0xf4, 0xc8, 0x47, 0x2e, 0xf7, 0x86, 0xf5, 0x87, 0x0b}; -static const uint8_t ECC384_TV0_SIG[96] = {0x98, 0x93, 0x5f, 0x0a, 0x05, 0x2c, 0xba, 0x3a, 0xd7, 0xd2, 0x08, 0xde, 0x64, 0xe7, 0x77, 0x2c, 0xbd, 0xe6, 0xd9, 0x16, 0x11, 0xd2, 0xef, 0x03, 0xba, 0x12, 0x9f, 0x14, 0x98, 0x49, 0x8c, 0x2d, 0x36, 0x50, 0xd9, 0xcf, 0xbb, 0x2b, 0xea, 0xcb, 0x28, 0xe7, 0x0b, 0x90, 0x43, 0x9e, 0x01, 0x8b, 0x52, 0xdb, 0x46, 0xec, 0xc7, 0xf6, 0xa9, 0x56, 0x88, 0x00, 0x3c, 0xdb, 0x4f, 0xfe, 0x04, 0xa1, 0xc7, 0x4c, 0x3f, 0xfc, 0xb8, 0xc8, 0x70, 0x42, 0x12, 0xf4, 0x37, 0xfa, 0xcd, 0xb9, 0x17, 0x2f, 0x60, 0x8c, 0xb6, 0x05, 0xc6, 0xce, 0x37, 0xd6, 0xc9, 0xf0, 0x0b, 0x23, 0x39, - 0x10, 0x29, 0x0d}; +static const uint8_t ECC384_TV0_PUBLIC[49] = { 0x02, 0xed, 0xbc, 0xbb, 0x1f, 0x23, 0x9b, 0xbd, 0x9d, 0x3d, + 0x7c, 0xef, 0x6b, 0x37, 0xa3, 0x26, 0x69, 0xe9, 0x4d, 0xf4, + 0x26, 0x64, 0xfb, 0xac, 0x76, 0x40, 0xc2, 0x22, 0x21, 0xa6, + 0xa3, 0xdf, 0x8c, 0x96, 0x81, 0x76, 0x0f, 0x0e, 0x67, 0xab, + 0xd4, 0x51, 0x58, 0xb3, 0x15, 0x63, 0xfb, 0x49, 0x71 }; +static const uint8_t ECC384_TV0_PRIVATE[48] = { + 0x62, 0x93, 0x9b, 0x4a, 0x29, 0x3c, 0xc6, 0x86, 0x98, 0xc3, 0xd0, 0x7f, 0xb7, 0xff, 0x97, 0xa2, + 0xfb, 0xc9, 0x36, 0x8a, 0x1d, 0xa5, 0x40, 0x8e, 0x49, 0x13, 0xd4, 0x15, 0x46, 0xcb, 0xb4, 0x08, + 0xfa, 0x8c, 0xb2, 0x7f, 0xcc, 0x3f, 0x72, 0xf8, 0x0d, 0x16, 0x7b, 0xf0, 0xa4, 0xc3, 0x29, 0xd3 +}; +static const uint8_t ECC384_TV0_DH_SELF_AGREE[48] = { 0xf6, 0x96, 0xbd, 0x1b, 0xda, 0x5e, 0x52, 0x8c, 0x1d, 0x56, + 0xa3, 0x6e, 0xd9, 0xba, 0xd7, 0x84, 0xdd, 0x20, 0x1b, 0x50, + 0xc9, 0xd8, 0x68, 0xb9, 0x52, 0x93, 0x27, 0xab, 0x17, 0xed, + 0xc6, 0xae, 0x89, 0x5e, 0x7f, 0xd9, 0x46, 0x15, 0x87, 0xf4, + 0xc8, 0x47, 0x2e, 0xf7, 0x86, 0xf5, 0x87, 0x0b }; +static const uint8_t ECC384_TV0_SIG[96] = { 0x98, 0x93, 0x5f, 0x0a, 0x05, 0x2c, 0xba, 0x3a, 0xd7, 0xd2, 0x08, 0xde, + 0x64, 0xe7, 0x77, 0x2c, 0xbd, 0xe6, 0xd9, 0x16, 0x11, 0xd2, 0xef, 0x03, + 0xba, 0x12, 0x9f, 0x14, 0x98, 0x49, 0x8c, 0x2d, 0x36, 0x50, 0xd9, 0xcf, + 0xbb, 0x2b, 0xea, 0xcb, 0x28, 0xe7, 0x0b, 0x90, 0x43, 0x9e, 0x01, 0x8b, + 0x52, 0xdb, 0x46, 0xec, 0xc7, 0xf6, 0xa9, 0x56, 0x88, 0x00, 0x3c, 0xdb, + 0x4f, 0xfe, 0x04, 0xa1, 0xc7, 0x4c, 0x3f, 0xfc, 0xb8, 0xc8, 0x70, 0x42, + 0x12, 0xf4, 0x37, 0xfa, 0xcd, 0xb9, 0x17, 0x2f, 0x60, 0x8c, 0xb6, 0x05, + 0xc6, 0xce, 0x37, 0xd6, 0xc9, 0xf0, 0x0b, 0x23, 0x39, 0x10, 0x29, 0x0d }; -static const uint8_t SALSA20_TV0_KEY[32] = {0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c}; -static const uint8_t SALSA20_TV0_IV[8] = {0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9}; -static const uint8_t SALSA20_TV0_KS[64] = {0x5e, 0x5e, 0x71, 0xf9, 0x01, 0x99, 0x34, 0x03, 0x04, 0xab, 0xb2, 0x2a, 0x37, 0xb6, 0x62, 0x5b, 0xf8, 0x83, 0xfb, 0x89, 0xce, 0x3b, 0x21, 0xf5, 0x4a, 0x10, 0xb8, 0x10, 0x66, 0xef, 0x87, 0xda, 0x30, 0xb7, 0x76, 0x99, 0xaa, 0x73, 0x79, 0xda, 0x59, 0x5c, 0x77, 0xdd, 0x59, 0x54, 0x2d, 0xa2, 0x08, 0xe5, 0x95, 0x4f, 0x89, 0xe4, 0x0e, 0xb7, 0xaa, 0x80, 0xa8, 0x4a, 0x61, 0x76, 0x66, 0x3f}; +static const uint8_t SALSA20_TV0_KEY[32] = { 0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, + 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, + 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c }; +static const uint8_t SALSA20_TV0_IV[8] = { 0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9 }; +static const uint8_t SALSA20_TV0_KS[64] = { 0x5e, 0x5e, 0x71, 0xf9, 0x01, 0x99, 0x34, 0x03, 0x04, 0xab, 0xb2, + 0x2a, 0x37, 0xb6, 0x62, 0x5b, 0xf8, 0x83, 0xfb, 0x89, 0xce, 0x3b, + 0x21, 0xf5, 0x4a, 0x10, 0xb8, 0x10, 0x66, 0xef, 0x87, 0xda, 0x30, + 0xb7, 0x76, 0x99, 0xaa, 0x73, 0x79, 0xda, 0x59, 0x5c, 0x77, 0xdd, + 0x59, 0x54, 0x2d, 0xa2, 0x08, 0xe5, 0x95, 0x4f, 0x89, 0xe4, 0x0e, + 0xb7, 0xaa, 0x80, 0xa8, 0x4a, 0x61, 0x76, 0x66, 0x3f }; -static const uint8_t SALSA12_TV0_KEY[32] = {0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c}; -static const uint8_t SALSA12_TV0_IV[8] = {0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9}; -static const uint8_t SALSA12_TV0_KS[64] = {0x99, 0xDB, 0x33, 0xAD, 0x11, 0xCE, 0x0C, 0xCB, 0x3B, 0xFD, 0xBF, 0x8D, 0x0C, 0x18, 0x16, 0x04, 0x52, 0xD0, 0x14, 0xCD, 0xE9, 0x89, 0xB4, 0xC4, 0x11, 0xA5, 0x59, 0xFF, 0x7C, 0x20, 0xA1, 0x69, 0xE6, 0xDC, 0x99, 0x09, 0xD8, 0x16, 0xBE, 0xCE, 0xDC, 0x40, 0x63, 0xCE, 0x07, 0xCE, 0xA8, 0x28, 0xF4, 0x4B, 0xF9, 0xB6, 0xC9, 0xA0, 0xA0, 0xB2, 0x00, 0xE1, 0xB5, 0x2A, 0xF4, 0x18, 0x59, 0xC5}; +static const uint8_t SALSA12_TV0_KEY[32] = { 0x0f, 0x62, 0xb5, 0x08, 0x5b, 0xae, 0x01, 0x54, 0xa7, 0xfa, 0x4d, + 0xa0, 0xf3, 0x46, 0x99, 0xec, 0x3f, 0x92, 0xe5, 0x38, 0x8b, 0xde, + 0x31, 0x84, 0xd7, 0x2a, 0x7d, 0xd0, 0x23, 0x76, 0xc9, 0x1c }; +static const uint8_t SALSA12_TV0_IV[8] = { 0x28, 0x8f, 0xf6, 0x5d, 0xc4, 0x2b, 0x92, 0xf9 }; +static const uint8_t SALSA12_TV0_KS[64] = { 0x99, 0xDB, 0x33, 0xAD, 0x11, 0xCE, 0x0C, 0xCB, 0x3B, 0xFD, 0xBF, + 0x8D, 0x0C, 0x18, 0x16, 0x04, 0x52, 0xD0, 0x14, 0xCD, 0xE9, 0x89, + 0xB4, 0xC4, 0x11, 0xA5, 0x59, 0xFF, 0x7C, 0x20, 0xA1, 0x69, 0xE6, + 0xDC, 0x99, 0x09, 0xD8, 0x16, 0xBE, 0xCE, 0xDC, 0x40, 0x63, 0xCE, + 0x07, 0xCE, 0xA8, 0x28, 0xF4, 0x4B, 0xF9, 0xB6, 0xC9, 0xA0, 0xA0, + 0xB2, 0x00, 0xE1, 0xB5, 0x2A, 0xF4, 0x18, 0x59, 0xC5 }; -static const uint8_t POLY1305_TV0_INPUT[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t POLY1305_TV0_KEY[32] = {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}; -static const uint8_t POLY1305_TV0_TAG[16] = {0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07}; +static const uint8_t POLY1305_TV0_INPUT[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t POLY1305_TV0_KEY[32] = { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35 }; +static const uint8_t POLY1305_TV0_TAG[16] = { 0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, + 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07 }; -static const uint8_t POLY1305_TV1_INPUT[12] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21}; -static const uint8_t POLY1305_TV1_KEY[32] = {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}; -static const uint8_t POLY1305_TV1_TAG[16] = {0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0}; +static const uint8_t POLY1305_TV1_INPUT[12] = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21 +}; +static const uint8_t POLY1305_TV1_KEY[32] = { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35 }; +static const uint8_t POLY1305_TV1_TAG[16] = { 0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, + 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0 }; -static const char *SHA512_TV0_INPUT = "supercalifragilisticexpealidocious"; -static const uint8_t SHA512_TV0_DIGEST[64] = {0x18, 0x2a, 0x85, 0x59, 0x69, 0xe5, 0xd3, 0xe6, 0xcb, 0xf6, 0x05, 0x24, 0xad, 0xf2, 0x88, 0xd1, 0xbb, 0xf2, 0x52, 0x92, 0x81, 0x24, 0x31, 0xf6, 0xd2, 0x52, 0xf1, 0xdb, 0xc1, 0xcb, 0x44, 0xdf, 0x21, 0x57, 0x3d, 0xe1, 0xb0, 0x6b, 0x68, 0x75, 0x95, 0x9f, 0x3b, 0x6f, 0x87, 0xb1, 0x13, 0x81, 0xd0, 0xbc, 0x79, 0x2c, 0x43, 0x3a, 0x13, 0x55, 0x3c, 0xe0, 0x84, 0xc2, 0x92, 0x55, 0x31, 0x1c}; -static const uint8_t SHA512_TV0_SHA384_DIGEST[48] = {0x71, 0xe7, 0x71, 0x79, 0xae, 0xc3, 0xf3, 0x5f, 0x93, 0xea, 0xe2, 0x1d, 0xe3, 0x3f, 0x24, 0x6d, 0xed, 0x2a, 0x59, 0xae, 0x22, 0x45, 0x27, 0x6c, 0x12, 0x57, 0xf3, 0xbe, 0xe6, 0xce, 0xe2, 0x73, 0xd8, 0xad, 0xaa, 0x9b, 0x99, 0xa4, 0x8a, 0x1b, 0x7a, 0xb9, 0x5d, 0xfb, 0x9c, 0x1a, 0x1c, 0xf6}; +static const char* SHA512_TV0_INPUT = "supercalifragilisticexpealidocious"; +static const uint8_t SHA512_TV0_DIGEST[64] = { 0x18, 0x2a, 0x85, 0x59, 0x69, 0xe5, 0xd3, 0xe6, 0xcb, 0xf6, 0x05, + 0x24, 0xad, 0xf2, 0x88, 0xd1, 0xbb, 0xf2, 0x52, 0x92, 0x81, 0x24, + 0x31, 0xf6, 0xd2, 0x52, 0xf1, 0xdb, 0xc1, 0xcb, 0x44, 0xdf, 0x21, + 0x57, 0x3d, 0xe1, 0xb0, 0x6b, 0x68, 0x75, 0x95, 0x9f, 0x3b, 0x6f, + 0x87, 0xb1, 0x13, 0x81, 0xd0, 0xbc, 0x79, 0x2c, 0x43, 0x3a, 0x13, + 0x55, 0x3c, 0xe0, 0x84, 0xc2, 0x92, 0x55, 0x31, 0x1c }; +static const uint8_t SHA512_TV0_SHA384_DIGEST[48] = { 0x71, 0xe7, 0x71, 0x79, 0xae, 0xc3, 0xf3, 0x5f, 0x93, 0xea, + 0xe2, 0x1d, 0xe3, 0x3f, 0x24, 0x6d, 0xed, 0x2a, 0x59, 0xae, + 0x22, 0x45, 0x27, 0x6c, 0x12, 0x57, 0xf3, 0xbe, 0xe6, 0xce, + 0xe2, 0x73, 0xd8, 0xad, 0xaa, 0x9b, 0x99, 0xa4, 0x8a, 0x1b, + 0x7a, 0xb9, 0x5d, 0xfb, 0x9c, 0x1a, 0x1c, 0xf6 }; -static const uint8_t AES_TEST_VECTOR_0_KEY[32] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; -static const uint8_t AES_TEST_VECTOR_0_IN[16] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}; -static const uint8_t AES_TEST_VECTOR_0_OUT[16] = {0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8}; +static const uint8_t AES_TEST_VECTOR_0_KEY[32] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, + 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, + 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }; +static const uint8_t AES_TEST_VECTOR_0_IN[16] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }; +static const uint8_t AES_TEST_VECTOR_0_OUT[16] = { 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, + 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8 }; -static const uint8_t AES_CTR_TEST_VECTOR_0_KEY[32] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; -static const uint8_t AES_CTR_TEST_VECTOR_0_IV[16] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}; -static const uint8_t AES_CTR_TEST_VECTOR_0_IN[64] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; -static const uint8_t AES_CTR_TEST_VECTOR_0_OUT[64] = {0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28, 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5, 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d, 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6}; +static const uint8_t AES_CTR_TEST_VECTOR_0_KEY[32] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, + 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, + 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }; +static const uint8_t AES_CTR_TEST_VECTOR_0_IV[16] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; +static const uint8_t AES_CTR_TEST_VECTOR_0_IN[64] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, + 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, + 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, + 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, + 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, + 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }; +static const uint8_t AES_CTR_TEST_VECTOR_0_OUT[64] = { 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, + 0x04, 0xbb, 0xf3, 0xd2, 0x28, 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, + 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5, 0x2b, + 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, + 0x2d, 0x84, 0x98, 0x8d, 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, + 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6 }; // Key and IV are same as test vector 0, input is a buffer filled by iterating 0..777 and setting to these &0xff -static const uint8_t AES_CTR_TEST_VECTOR_1_OUT[777] = {0x0b, 0xde, 0x7f, 0xf2, 0x5d, 0x12, 0x10, 0x34, 0x56, 0x93, 0x81, 0x1e, 0xc4, 0x6d, 0xcb, 0x0d, 0x4a, 0x7f, 0x7b, 0x8e, 0x47, 0x74, 0x0f, 0x11, 0x4c, 0x2a, 0x9c, 0x27, 0x93, 0x78, 0x65, 0x8b, 0x3b, 0xe0, 0x0e, 0xbf, 0x25, 0x44, 0x2b, 0x7a, 0x25, 0xa2, 0xfc, 0x88, 0x1b, 0xa3, 0xe4, 0x4d, 0x19, 0x67, 0xd3, 0xfb, 0x5d, 0x00, 0x00, 0x86, 0x86, 0xd0, 0xa6, 0x48, 0x9f, 0x28, 0x48, 0x89, 0xcb, 0x36, 0xbd, 0xa3, 0x9d, 0x39, 0x4f, 0xd5, 0x9f, 0xbe, 0x44, 0x57, 0xa5, 0x82, 0x8d, 0xf8, 0x1c, 0xba, 0x35, 0xd1, 0x34, 0x53, 0x5e, 0xd4, 0x34, 0xfb, 0x91, - 0x1e, 0x79, 0xc7, 0xdb, 0xf2, 0x79, 0xaf, 0x31, 0x9f, 0x54, 0x70, 0xe7, 0x15, 0xbd, 0x3e, 0x76, 0x2b, 0x82, 0x2c, 0x37, 0x07, 0x44, 0x1e, 0x5b, 0x7a, 0xca, 0xb8, 0x17, 0x74, 0x1c, 0x5e, 0xa6, 0xe0, 0x57, 0xaa, 0x13, 0x99, 0x5e, 0x3c, 0x11, 0xfe, 0xce, 0xeb, 0x6b, 0x8e, 0x5e, 0xc6, 0x79, 0xa2, 0xa7, 0x4c, 0x00, 0xff, 0x0a, 0x5d, 0xbb, 0x3b, 0xc5, 0x76, 0xe7, 0x9a, 0x53, 0x76, 0x67, 0xee, 0x8e, 0x73, 0x80, 0xa8, 0x6d, 0xad, 0x38, 0x73, 0x62, 0x71, 0x76, 0x8a, 0x3d, 0x5e, 0x42, 0xae, 0xb8, 0x7d, 0x61, 0xd3, 0x1d, 0x97, 0xd7, 0xda, 0x51, 0xf5, - 0x89, 0x26, 0xed, 0x45, 0x75, 0x88, 0x65, 0x69, 0x06, 0xe8, 0x3d, 0x31, 0x82, 0xe0, 0xa4, 0x82, 0x79, 0xf0, 0x44, 0x7c, 0x36, 0x4a, 0xd0, 0x25, 0x13, 0x30, 0x1a, 0x1e, 0x52, 0x5c, 0x0e, 0xe4, 0x68, 0x93, 0xbf, 0x1e, 0x5a, 0x43, 0xc1, 0xe6, 0x7f, 0x8a, 0xf7, 0xff, 0xb8, 0x95, 0x41, 0x6b, 0x28, 0xbc, 0x2a, 0xac, 0x9e, 0x8e, 0x7f, 0x7c, 0xc1, 0xd9, 0xed, 0x0b, 0x52, 0x55, 0x28, 0x6c, 0xb4, 0x15, 0x96, 0xbe, 0xfc, 0xe9, 0xfd, 0x3a, 0x84, 0xc9, 0xd6, 0x4f, 0x40, 0xe4, 0xe0, 0x59, 0xc4, 0xfe, 0x62, 0x8a, 0x2c, 0xbb, 0xcd, 0xc2, 0x5b, 0x4b, 0x53, - 0x67, 0x0d, 0xc3, 0x6d, 0x0f, 0x67, 0xfe, 0x20, 0x77, 0x43, 0x98, 0x92, 0x13, 0x15, 0x0f, 0x9b, 0x2c, 0x4b, 0xa9, 0x53, 0x2a, 0xb2, 0xd0, 0x72, 0x64, 0x5e, 0x92, 0x7f, 0x25, 0xde, 0x0a, 0x93, 0x46, 0x03, 0x33, 0xdc, 0x43, 0x4f, 0xfa, 0x00, 0x8a, 0xfc, 0xcb, 0x42, 0x3d, 0x5f, 0x25, 0xbc, 0xa2, 0x78, 0xdd, 0x3d, 0x0c, 0x82, 0x52, 0xd8, 0x0a, 0x32, 0xee, 0xc7, 0xd8, 0x46, 0x24, 0x63, 0xc3, 0x33, 0xba, 0x66, 0x0b, 0x20, 0x74, 0xc6, 0x06, 0x5b, 0x2c, 0xea, 0x06, 0xed, 0x36, 0xda, 0xbc, 0x3f, 0x0a, 0xb0, 0xa5, 0xad, 0xd0, 0xd6, 0x9a, 0x33, 0x49, - 0xbe, 0xb6, 0x94, 0xa2, 0xef, 0x82, 0xa4, 0x1b, 0x81, 0x71, 0xb9, 0xea, 0x37, 0xfe, 0x43, 0x48, 0xa1, 0x30, 0x92, 0x6f, 0x69, 0x45, 0xc6, 0xf7, 0xdd, 0x0d, 0x10, 0x3b, 0x71, 0x59, 0x8c, 0xfc, 0x18, 0xf2, 0x48, 0x21, 0xf3, 0x6c, 0xa8, 0xaa, 0x33, 0xff, 0xf4, 0x38, 0x96, 0x5b, 0x34, 0x43, 0x7f, 0xcc, 0x9c, 0x87, 0x36, 0x3b, 0x96, 0x3e, 0x1a, 0xbf, 0x6d, 0xa1, 0x89, 0x42, 0xb3, 0xb9, 0x64, 0x9e, 0xa3, 0xef, 0x36, 0x4a, 0x41, 0xb9, 0xa3, 0xb9, 0xad, 0xa4, 0xd9, 0x33, 0xad, 0xa5, 0xba, 0x41, 0x83, 0x12, 0xc5, 0x92, 0xf8, 0x6a, 0x10, 0x20, 0x1e, - 0xe0, 0xfd, 0xe8, 0x6d, 0xfc, 0x4a, 0x7c, 0x72, 0x7f, 0x54, 0x4d, 0x00, 0xd5, 0x3e, 0x6a, 0x28, 0x94, 0x11, 0x8a, 0x38, 0xef, 0xb5, 0xb6, 0xf3, 0xbf, 0xd2, 0xbe, 0xf3, 0x1e, 0x8b, 0xe8, 0x0c, 0xf2, 0x9d, 0xaf, 0xff, 0x90, 0x4c, 0x8a, 0x44, 0xad, 0xd9, 0x8b, 0x99, 0x47, 0x65, 0x31, 0x74, 0xb2, 0x24, 0xb3, 0x6d, 0xd3, 0x4a, 0x4c, 0x19, 0xf6, 0x2f, 0x53, 0x2d, 0xb8, 0x05, 0xd3, 0x7d, 0x53, 0xc9, 0xc7, 0x7e, 0x03, 0xeb, 0xfc, 0x18, 0x36, 0xe2, 0x4b, 0xcf, 0xfd, 0xe8, 0x97, 0xde, 0xd8, 0x42, 0x80, 0x05, 0x77, 0x8c, 0xec, 0x15, 0xae, 0x23, 0x13, - 0xe8, 0xa5, 0x1c, 0xca, 0x30, 0x60, 0x8c, 0x20, 0x86, 0xdf, 0xa0, 0xd7, 0x88, 0x2c, 0x27, 0xa0, 0x8f, 0x99, 0x23, 0x9c, 0x11, 0xa9, 0xe6, 0x4a, 0xfc, 0x0a, 0x89, 0xa4, 0x60, 0x94, 0xa9, 0x2e, 0x40, 0x62, 0x22, 0xd2, 0xae, 0x31, 0x4b, 0x52, 0x2c, 0x5f, 0x9a, 0xd6, 0x54, 0x58, 0x08, 0xa1, 0x97, 0x1c, 0x28, 0xef, 0x53, 0x5d, 0x6a, 0x4b, 0x07, 0xe7, 0x62, 0x06, 0xb2, 0xa8, 0xb4, 0x12, 0x9a, 0x10, 0x12, 0xa2, 0xe3, 0x02, 0xce, 0xc3, 0xa7, 0x73, 0x47, 0xf1, 0xfb, 0xcb, 0x77, 0xb5, 0x33, 0x81, 0xb9, 0xf7, 0x79, 0x1d, 0x93, 0x2d, 0x2e, 0x14, 0x94, - 0x05, 0x36, 0xe1, 0x41, 0xcd, 0xdc, 0x83, 0x05, 0xea, 0xac, 0x61, 0xe9, 0xe5, 0xc2, 0x7d, 0x53, 0x44, 0x65, 0x8a, 0x25, 0x0d, 0xb4, 0x66, 0x43, 0x5c, 0xbf, 0x6d, 0x7f, 0xc0, 0x46, 0xab, 0xab, 0xfb, 0x0e, 0xd2, 0x33, 0xdf, 0x67, 0x0a, 0x1f, 0x29, 0x29, 0x6c, 0x1d, 0x32, 0x7d, 0x3a, 0xff, 0x10, 0x59, 0x10, 0x79, 0x68, 0x0a, 0x04, 0x0d, 0x1c, 0x4e, 0xe0, 0x6d, 0x1b, 0x59, 0xfc, 0x23, 0x6b, 0x9c, 0x6a, 0xde, 0x1f, 0x1c, 0x9f, 0x0c, 0x1c, 0x8f, 0x5e, 0xd1, 0x64, 0x7e, 0x33, 0x2f, 0xae, 0xdf, 0x76, 0x87, 0xab, 0x64, 0x04, 0xd2, 0xc3, 0xfe, 0x4f, - 0x95, 0x47, 0xf2, 0x16, 0x11, 0xdb, 0x00, 0x56, 0xb4, 0x96, 0x0f, 0x1e, 0x18, 0xc6, 0xcd, 0xa3, 0x29, 0x8e, 0xd0, 0xf3, 0x0f, 0x85, 0x2f, 0xa0, 0xe7, 0x8c, 0x12, 0x2c, 0xdc, 0x85, 0x0b, 0xef, 0xb3, 0x7d, 0x59, 0x87, 0xaa, 0x1d, 0xfc, 0xde, 0xd0, 0xbc, 0x4c, 0xe8, 0x49, 0x11, 0x50, 0xf5, 0x7f}; +static const uint8_t AES_CTR_TEST_VECTOR_1_OUT[777] = { + 0x0b, 0xde, 0x7f, 0xf2, 0x5d, 0x12, 0x10, 0x34, 0x56, 0x93, 0x81, 0x1e, 0xc4, 0x6d, 0xcb, 0x0d, 0x4a, 0x7f, 0x7b, + 0x8e, 0x47, 0x74, 0x0f, 0x11, 0x4c, 0x2a, 0x9c, 0x27, 0x93, 0x78, 0x65, 0x8b, 0x3b, 0xe0, 0x0e, 0xbf, 0x25, 0x44, + 0x2b, 0x7a, 0x25, 0xa2, 0xfc, 0x88, 0x1b, 0xa3, 0xe4, 0x4d, 0x19, 0x67, 0xd3, 0xfb, 0x5d, 0x00, 0x00, 0x86, 0x86, + 0xd0, 0xa6, 0x48, 0x9f, 0x28, 0x48, 0x89, 0xcb, 0x36, 0xbd, 0xa3, 0x9d, 0x39, 0x4f, 0xd5, 0x9f, 0xbe, 0x44, 0x57, + 0xa5, 0x82, 0x8d, 0xf8, 0x1c, 0xba, 0x35, 0xd1, 0x34, 0x53, 0x5e, 0xd4, 0x34, 0xfb, 0x91, 0x1e, 0x79, 0xc7, 0xdb, + 0xf2, 0x79, 0xaf, 0x31, 0x9f, 0x54, 0x70, 0xe7, 0x15, 0xbd, 0x3e, 0x76, 0x2b, 0x82, 0x2c, 0x37, 0x07, 0x44, 0x1e, + 0x5b, 0x7a, 0xca, 0xb8, 0x17, 0x74, 0x1c, 0x5e, 0xa6, 0xe0, 0x57, 0xaa, 0x13, 0x99, 0x5e, 0x3c, 0x11, 0xfe, 0xce, + 0xeb, 0x6b, 0x8e, 0x5e, 0xc6, 0x79, 0xa2, 0xa7, 0x4c, 0x00, 0xff, 0x0a, 0x5d, 0xbb, 0x3b, 0xc5, 0x76, 0xe7, 0x9a, + 0x53, 0x76, 0x67, 0xee, 0x8e, 0x73, 0x80, 0xa8, 0x6d, 0xad, 0x38, 0x73, 0x62, 0x71, 0x76, 0x8a, 0x3d, 0x5e, 0x42, + 0xae, 0xb8, 0x7d, 0x61, 0xd3, 0x1d, 0x97, 0xd7, 0xda, 0x51, 0xf5, 0x89, 0x26, 0xed, 0x45, 0x75, 0x88, 0x65, 0x69, + 0x06, 0xe8, 0x3d, 0x31, 0x82, 0xe0, 0xa4, 0x82, 0x79, 0xf0, 0x44, 0x7c, 0x36, 0x4a, 0xd0, 0x25, 0x13, 0x30, 0x1a, + 0x1e, 0x52, 0x5c, 0x0e, 0xe4, 0x68, 0x93, 0xbf, 0x1e, 0x5a, 0x43, 0xc1, 0xe6, 0x7f, 0x8a, 0xf7, 0xff, 0xb8, 0x95, + 0x41, 0x6b, 0x28, 0xbc, 0x2a, 0xac, 0x9e, 0x8e, 0x7f, 0x7c, 0xc1, 0xd9, 0xed, 0x0b, 0x52, 0x55, 0x28, 0x6c, 0xb4, + 0x15, 0x96, 0xbe, 0xfc, 0xe9, 0xfd, 0x3a, 0x84, 0xc9, 0xd6, 0x4f, 0x40, 0xe4, 0xe0, 0x59, 0xc4, 0xfe, 0x62, 0x8a, + 0x2c, 0xbb, 0xcd, 0xc2, 0x5b, 0x4b, 0x53, 0x67, 0x0d, 0xc3, 0x6d, 0x0f, 0x67, 0xfe, 0x20, 0x77, 0x43, 0x98, 0x92, + 0x13, 0x15, 0x0f, 0x9b, 0x2c, 0x4b, 0xa9, 0x53, 0x2a, 0xb2, 0xd0, 0x72, 0x64, 0x5e, 0x92, 0x7f, 0x25, 0xde, 0x0a, + 0x93, 0x46, 0x03, 0x33, 0xdc, 0x43, 0x4f, 0xfa, 0x00, 0x8a, 0xfc, 0xcb, 0x42, 0x3d, 0x5f, 0x25, 0xbc, 0xa2, 0x78, + 0xdd, 0x3d, 0x0c, 0x82, 0x52, 0xd8, 0x0a, 0x32, 0xee, 0xc7, 0xd8, 0x46, 0x24, 0x63, 0xc3, 0x33, 0xba, 0x66, 0x0b, + 0x20, 0x74, 0xc6, 0x06, 0x5b, 0x2c, 0xea, 0x06, 0xed, 0x36, 0xda, 0xbc, 0x3f, 0x0a, 0xb0, 0xa5, 0xad, 0xd0, 0xd6, + 0x9a, 0x33, 0x49, 0xbe, 0xb6, 0x94, 0xa2, 0xef, 0x82, 0xa4, 0x1b, 0x81, 0x71, 0xb9, 0xea, 0x37, 0xfe, 0x43, 0x48, + 0xa1, 0x30, 0x92, 0x6f, 0x69, 0x45, 0xc6, 0xf7, 0xdd, 0x0d, 0x10, 0x3b, 0x71, 0x59, 0x8c, 0xfc, 0x18, 0xf2, 0x48, + 0x21, 0xf3, 0x6c, 0xa8, 0xaa, 0x33, 0xff, 0xf4, 0x38, 0x96, 0x5b, 0x34, 0x43, 0x7f, 0xcc, 0x9c, 0x87, 0x36, 0x3b, + 0x96, 0x3e, 0x1a, 0xbf, 0x6d, 0xa1, 0x89, 0x42, 0xb3, 0xb9, 0x64, 0x9e, 0xa3, 0xef, 0x36, 0x4a, 0x41, 0xb9, 0xa3, + 0xb9, 0xad, 0xa4, 0xd9, 0x33, 0xad, 0xa5, 0xba, 0x41, 0x83, 0x12, 0xc5, 0x92, 0xf8, 0x6a, 0x10, 0x20, 0x1e, 0xe0, + 0xfd, 0xe8, 0x6d, 0xfc, 0x4a, 0x7c, 0x72, 0x7f, 0x54, 0x4d, 0x00, 0xd5, 0x3e, 0x6a, 0x28, 0x94, 0x11, 0x8a, 0x38, + 0xef, 0xb5, 0xb6, 0xf3, 0xbf, 0xd2, 0xbe, 0xf3, 0x1e, 0x8b, 0xe8, 0x0c, 0xf2, 0x9d, 0xaf, 0xff, 0x90, 0x4c, 0x8a, + 0x44, 0xad, 0xd9, 0x8b, 0x99, 0x47, 0x65, 0x31, 0x74, 0xb2, 0x24, 0xb3, 0x6d, 0xd3, 0x4a, 0x4c, 0x19, 0xf6, 0x2f, + 0x53, 0x2d, 0xb8, 0x05, 0xd3, 0x7d, 0x53, 0xc9, 0xc7, 0x7e, 0x03, 0xeb, 0xfc, 0x18, 0x36, 0xe2, 0x4b, 0xcf, 0xfd, + 0xe8, 0x97, 0xde, 0xd8, 0x42, 0x80, 0x05, 0x77, 0x8c, 0xec, 0x15, 0xae, 0x23, 0x13, 0xe8, 0xa5, 0x1c, 0xca, 0x30, + 0x60, 0x8c, 0x20, 0x86, 0xdf, 0xa0, 0xd7, 0x88, 0x2c, 0x27, 0xa0, 0x8f, 0x99, 0x23, 0x9c, 0x11, 0xa9, 0xe6, 0x4a, + 0xfc, 0x0a, 0x89, 0xa4, 0x60, 0x94, 0xa9, 0x2e, 0x40, 0x62, 0x22, 0xd2, 0xae, 0x31, 0x4b, 0x52, 0x2c, 0x5f, 0x9a, + 0xd6, 0x54, 0x58, 0x08, 0xa1, 0x97, 0x1c, 0x28, 0xef, 0x53, 0x5d, 0x6a, 0x4b, 0x07, 0xe7, 0x62, 0x06, 0xb2, 0xa8, + 0xb4, 0x12, 0x9a, 0x10, 0x12, 0xa2, 0xe3, 0x02, 0xce, 0xc3, 0xa7, 0x73, 0x47, 0xf1, 0xfb, 0xcb, 0x77, 0xb5, 0x33, + 0x81, 0xb9, 0xf7, 0x79, 0x1d, 0x93, 0x2d, 0x2e, 0x14, 0x94, 0x05, 0x36, 0xe1, 0x41, 0xcd, 0xdc, 0x83, 0x05, 0xea, + 0xac, 0x61, 0xe9, 0xe5, 0xc2, 0x7d, 0x53, 0x44, 0x65, 0x8a, 0x25, 0x0d, 0xb4, 0x66, 0x43, 0x5c, 0xbf, 0x6d, 0x7f, + 0xc0, 0x46, 0xab, 0xab, 0xfb, 0x0e, 0xd2, 0x33, 0xdf, 0x67, 0x0a, 0x1f, 0x29, 0x29, 0x6c, 0x1d, 0x32, 0x7d, 0x3a, + 0xff, 0x10, 0x59, 0x10, 0x79, 0x68, 0x0a, 0x04, 0x0d, 0x1c, 0x4e, 0xe0, 0x6d, 0x1b, 0x59, 0xfc, 0x23, 0x6b, 0x9c, + 0x6a, 0xde, 0x1f, 0x1c, 0x9f, 0x0c, 0x1c, 0x8f, 0x5e, 0xd1, 0x64, 0x7e, 0x33, 0x2f, 0xae, 0xdf, 0x76, 0x87, 0xab, + 0x64, 0x04, 0xd2, 0xc3, 0xfe, 0x4f, 0x95, 0x47, 0xf2, 0x16, 0x11, 0xdb, 0x00, 0x56, 0xb4, 0x96, 0x0f, 0x1e, 0x18, + 0xc6, 0xcd, 0xa3, 0x29, 0x8e, 0xd0, 0xf3, 0x0f, 0x85, 0x2f, 0xa0, 0xe7, 0x8c, 0x12, 0x2c, 0xdc, 0x85, 0x0b, 0xef, + 0xb3, 0x7d, 0x59, 0x87, 0xaa, 0x1d, 0xfc, 0xde, 0xd0, 0xbc, 0x4c, 0xe8, 0x49, 0x11, 0x50, 0xf5, 0x7f +}; -static const uint8_t AES_GMAC_VECTOR_0_KEY[32] = {0xbb, 0x10, 0x10, 0x06, 0x4f, 0xb8, 0x35, 0x23, 0xea, 0x9d, 0xf3, 0x2b, 0xad, 0x9f, 0x1f, 0x2a, 0x4f, 0xce, 0xfc, 0x0f, 0x21, 0x07, 0xc0, 0xaa, 0xba, 0xd9, 0xb7, 0x56, 0xd8, 0x09, 0x21, 0x9d}; -static const uint8_t AES_GMAC_VECTOR_0_IV[12] = {0x2f, 0x9a, 0xd0, 0x12, 0xad, 0xfc, 0x12, 0x73, 0x43, 0xfb, 0xe0, 0x56}; -static const uint8_t AES_GMAC_VECTOR_0_IN[16] = {0xdb, 0x98, 0xd9, 0x0d, 0x1b, 0x69, 0x5c, 0xdb, 0x74, 0x7a, 0x34, 0x3f, 0xbb, 0xc9, 0xf1, 0x41}; -static const uint8_t AES_GMAC_VECTOR_0_OUT[16] = {0xef, 0x06, 0xd5, 0x4d, 0xfd, 0x00, 0x02, 0x1d, 0x75, 0x27, 0xdf, 0xf2, 0x6f, 0xc9, 0xd4, 0x84}; +static const uint8_t AES_GMAC_VECTOR_0_KEY[32] = { 0xbb, 0x10, 0x10, 0x06, 0x4f, 0xb8, 0x35, 0x23, 0xea, 0x9d, 0xf3, + 0x2b, 0xad, 0x9f, 0x1f, 0x2a, 0x4f, 0xce, 0xfc, 0x0f, 0x21, 0x07, + 0xc0, 0xaa, 0xba, 0xd9, 0xb7, 0x56, 0xd8, 0x09, 0x21, 0x9d }; +static const uint8_t AES_GMAC_VECTOR_0_IV[12] = { + 0x2f, 0x9a, 0xd0, 0x12, 0xad, 0xfc, 0x12, 0x73, 0x43, 0xfb, 0xe0, 0x56 +}; +static const uint8_t AES_GMAC_VECTOR_0_IN[16] = { 0xdb, 0x98, 0xd9, 0x0d, 0x1b, 0x69, 0x5c, 0xdb, + 0x74, 0x7a, 0x34, 0x3f, 0xbb, 0xc9, 0xf1, 0x41 }; +static const uint8_t AES_GMAC_VECTOR_0_OUT[16] = { 0xef, 0x06, 0xd5, 0x4d, 0xfd, 0x00, 0x02, 0x1d, + 0x75, 0x27, 0xdf, 0xf2, 0x6f, 0xc9, 0xd4, 0x84 }; -static const uint8_t AES_GMAC_VECTOR_1_KEY[32] = {0x83, 0xC0, 0x93, 0xB5, 0x8D, 0xE7, 0xFF, 0xE1, 0xC0, 0xDA, 0x92, 0x6A, 0xC4, 0x3F, 0xB3, 0x60, 0x9A, 0xC1, 0xC8, 0x0F, 0xEE, 0x1B, 0x62, 0x44, 0x97, 0xEF, 0x94, 0x2E, 0x2F, 0x79, 0xA8, 0x23}; -static const uint8_t AES_GMAC_VECTOR_1_IV[12] = {0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12}; -static const uint8_t AES_GMAC_VECTOR_1_IN[81] = {0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5, 0x23, 0x00, 0x89, 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00, 0x05}; -static const uint8_t AES_GMAC_VECTOR_1_OUT[16] = {0x6E, 0xE1, 0x60, 0xE8, 0xFA, 0xEC, 0xA4, 0xB3, 0x6C, 0x86, 0xB2, 0x34, 0x92, 0x0C, 0xA9, 0x75}; +static const uint8_t AES_GMAC_VECTOR_1_KEY[32] = { 0x83, 0xC0, 0x93, 0xB5, 0x8D, 0xE7, 0xFF, 0xE1, 0xC0, 0xDA, 0x92, + 0x6A, 0xC4, 0x3F, 0xB3, 0x60, 0x9A, 0xC1, 0xC8, 0x0F, 0xEE, 0x1B, + 0x62, 0x44, 0x97, 0xEF, 0x94, 0x2E, 0x2F, 0x79, 0xA8, 0x23 }; +static const uint8_t AES_GMAC_VECTOR_1_IV[12] = { + 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12 +}; +static const uint8_t AES_GMAC_VECTOR_1_IN[81] = { + 0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5, 0x23, 0x00, 0x89, + 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00, 0x05 +}; +static const uint8_t AES_GMAC_VECTOR_1_OUT[16] = { 0x6E, 0xE1, 0x60, 0xE8, 0xFA, 0xEC, 0xA4, 0xB3, + 0x6C, 0x86, 0xB2, 0x34, 0x92, 0x0C, 0xA9, 0x75 }; -static const uint8_t AES_GMAC_VECTOR_2_KEY[32] = {0x63, 0x2f, 0xd9, 0x48, 0xcf, 0x70, 0xe2, 0xee, 0x70, 0x63, 0xe8, 0x7a, 0x4a, 0x2a, 0x39, 0x9b, 0x67, 0x08, 0x64, 0x03, 0x68, 0x9d, 0xbc, 0x60, 0xea, 0x68, 0x4a, 0x7a, 0x83, 0x37, 0x00, 0xfe}; -static const uint8_t AES_GMAC_VECTOR_2_IV[12] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}; -static const uint8_t AES_GMAC_VECTOR_2_IN[541] = {0xc8, 0x36, 0x38, 0xe8, 0x53, 0xc8, 0x86, 0xa3, 0xe3, 0xad, 0x9e, 0x2a, 0x91, 0x47, 0xb9, 0x51, 0xad, 0xf7, 0x78, 0x89, 0x9a, 0xeb, 0x80, 0x41, 0x67, 0xa9, 0x16, 0xc4, 0x93, 0xcc, 0x77, 0x3d, 0x8c, 0xcf, 0x4d, 0xb5, 0x0b, 0xda, 0xfd, 0xc2, 0x8c, 0x83, 0x5d, 0x66, 0x43, 0x74, 0x21, 0xbd, 0xc4, 0xab, 0x41, 0xd8, 0x40, 0x53, 0x34, 0xe8, 0x05, 0xcb, 0x89, 0x45, 0x09, 0xb0, 0xa4, 0xa6, 0x04, 0x95, 0x19, 0x2c, 0xab, 0x94, 0xe1, 0x8d, 0x7b, 0x59, 0x8b, 0xb9, 0x31, 0xae, 0x3c, 0x25, 0xd3, 0x23, 0xab, 0x8f, 0x95, 0xa3, 0x8b, 0xa5, 0xc1, 0x66, 0x8b, - 0x57, 0xe4, 0x88, 0x70, 0xc9, 0xe0, 0xa1, 0x16, 0x39, 0xf8, 0x12, 0xb3, 0xe5, 0x95, 0x38, 0x3a, 0x01, 0x1d, 0xcc, 0xc0, 0xc3, 0xa9, 0x1c, 0x72, 0xa7, 0x46, 0x79, 0x51, 0x05, 0xb2, 0x85, 0x5a, 0x97, 0x16, 0x97, 0xa6, 0x85, 0xa4, 0xf2, 0x0b, 0x3c, 0x90, 0x52, 0xa3, 0xe0, 0xbe, 0xad, 0x06, 0x1b, 0x8e, 0x04, 0x22, 0xeb, 0x3a, 0x48, 0xb9, 0x84, 0x24, 0x0b, 0x24, 0x42, 0xd9, 0xed, 0x6b, 0x5c, 0xc1, 0xb6, 0x2e, 0xa5, 0xc0, 0x07, 0xfe, 0x3e, 0xbc, 0x9a, 0x92, 0x26, 0xb5, 0xa6, 0x5f, 0x09, 0x13, 0x85, 0x5a, 0xcf, 0x61, 0x56, 0x65, 0x0f, 0x4c, 0x64, - 0x79, 0xfa, 0x0a, 0xcf, 0xc0, 0x95, 0x8d, 0x4d, 0xc6, 0xbe, 0xee, 0xb3, 0x67, 0xd8, 0xa7, 0x40, 0x90, 0x61, 0xe3, 0xba, 0xcb, 0x18, 0xe0, 0x61, 0x7b, 0x33, 0x86, 0xf7, 0xef, 0x64, 0xe5, 0x36, 0xf0, 0x9c, 0xb6, 0x34, 0xb1, 0xe1, 0x2a, 0xd8, 0xd8, 0x5e, 0x6b, 0x61, 0x92, 0xa0, 0x8e, 0x04, 0x7b, 0xbf, 0xa5, 0x84, 0x39, 0x3a, 0xe0, 0x27, 0xc7, 0xb0, 0x83, 0x88, 0x4f, 0x3e, 0x49, 0x14, 0xaa, 0x34, 0xde, 0xb4, 0xbb, 0x4c, 0xe4, 0xbf, 0xae, 0x9a, 0xf9, 0x88, 0x7a, 0x1f, 0x18, 0xa0, 0x8c, 0x60, 0xc0, 0x5c, 0x46, 0xa1, 0xd1, 0x36, 0x99, 0x60, 0x9b, - 0x73, 0xa2, 0x9a, 0x0b, 0x8d, 0x6e, 0x2f, 0xe1, 0x58, 0x7a, 0x39, 0x71, 0xed, 0xfc, 0x34, 0xe4, 0x98, 0x57, 0x7e, 0x86, 0xf1, 0xe5, 0x00, 0x7d, 0x1b, 0x6a, 0xfa, 0xf8, 0x6e, 0x7b, 0x12, 0x44, 0x04, 0x60, 0x02, 0x81, 0x12, 0x09, 0x00, 0xb4, 0x35, 0x9e, 0x03, 0x73, 0x79, 0x9b, 0x13, 0xc5, 0xd7, 0x0e, 0xce, 0x49, 0x87, 0x48, 0x1a, 0x67, 0x89, 0x93, 0xef, 0xd1, 0xdf, 0x2d, 0x48, 0x6d, 0x30, 0xd5, 0xec, 0x49, 0xfe, 0x15, 0x1b, 0xa6, 0x2b, 0x6c, 0x08, 0x8e, 0x39, 0x73, 0x68, 0x87, 0xa7, 0x43, 0x28, 0x16, 0x77, 0x86, 0xd1, 0xcb, 0x13, 0xe4, 0xd3, - 0xda, 0x63, 0xcd, 0x3a, 0x2a, 0x35, 0xd5, 0xfa, 0x36, 0x67, 0xc8, 0x4c, 0x6b, 0xa1, 0x8a, 0xaf, 0x7b, 0x4c, 0x43, 0xb0, 0x2f, 0x4a, 0xcc, 0xc0, 0x11, 0xc6, 0x30, 0x8e, 0xa3, 0xd2, 0x4a, 0x1b, 0x2a, 0x4f, 0xec, 0x97, 0x83, 0xa6, 0x4c, 0xee, 0x51, 0xaf, 0x06, 0x0a, 0x1d, 0x80, 0xd9, 0xcf, 0xb7, 0x69, 0x23, 0x15, 0x3a, 0x26, 0x04, 0x34, 0x33, 0x76, 0x30, 0x9f, 0xfb, 0x56, 0xb4, 0x26, 0xee, 0xfa, 0x54, 0x6c, 0x18, 0xf9, 0xd5, 0x32, 0x5d, 0x03, 0xcb, 0x2c, 0x20, 0x30, 0x0c, 0xa0, 0xbb, 0xde, 0x01, 0x77, 0x65, 0xb0, 0x18, 0x30, 0xd2, 0x55, 0x9f, - 0x9b, 0xcf, 0xb8, 0x9b, 0xb4, 0xbc, 0x0b, 0x49, 0x52, 0x53, 0x30, 0x48, 0xa5, 0x12, 0xe5, 0x3b, 0x47, 0x84, 0xff, 0xf1, 0x53, 0x5d, 0x5c, 0x04, 0x70, 0x63, 0x91, 0xc3, 0xc0, 0xf0, 0xea, 0xcb, 0x44, 0x4f, 0x8c, 0x85, 0x42, 0x6a, 0xc7, 0xfa, 0xc7, 0xb5, 0x30, 0x03, 0x12, 0x65, 0xca, 0xba, 0x4f, 0x67, 0xbb, 0xef, 0xb6, 0xc6, 0x3f, 0x19, 0xe2, 0xb5, 0x4b, 0x8c, 0xfc, 0x9e, 0x18, 0xb0, 0x33, 0x89, 0x6e, 0xde, 0x61, 0x0a, 0xe3, 0x5e, 0xa3, 0x5d, 0x2e, 0x80, 0x3e, 0x53, 0x67, 0xfb, 0x7b, 0x7a, 0xbf, 0xd5, 0xf4, 0x47}; -static const uint8_t AES_GMAC_VECTOR_2_OUT[16] = {0x67, 0x39, 0x4f, 0x00, 0x04, 0x28, 0xaf, 0xe9, 0xb4, 0x2e, 0xb5, 0x3c, 0x42, 0x24, 0x86, 0xa3}; +static const uint8_t AES_GMAC_VECTOR_2_KEY[32] = { 0x63, 0x2f, 0xd9, 0x48, 0xcf, 0x70, 0xe2, 0xee, 0x70, 0x63, 0xe8, + 0x7a, 0x4a, 0x2a, 0x39, 0x9b, 0x67, 0x08, 0x64, 0x03, 0x68, 0x9d, + 0xbc, 0x60, 0xea, 0x68, 0x4a, 0x7a, 0x83, 0x37, 0x00, 0xfe }; +static const uint8_t AES_GMAC_VECTOR_2_IV[12] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b +}; +static const uint8_t AES_GMAC_VECTOR_2_IN[541] = { + 0xc8, 0x36, 0x38, 0xe8, 0x53, 0xc8, 0x86, 0xa3, 0xe3, 0xad, 0x9e, 0x2a, 0x91, 0x47, 0xb9, 0x51, 0xad, 0xf7, 0x78, + 0x89, 0x9a, 0xeb, 0x80, 0x41, 0x67, 0xa9, 0x16, 0xc4, 0x93, 0xcc, 0x77, 0x3d, 0x8c, 0xcf, 0x4d, 0xb5, 0x0b, 0xda, + 0xfd, 0xc2, 0x8c, 0x83, 0x5d, 0x66, 0x43, 0x74, 0x21, 0xbd, 0xc4, 0xab, 0x41, 0xd8, 0x40, 0x53, 0x34, 0xe8, 0x05, + 0xcb, 0x89, 0x45, 0x09, 0xb0, 0xa4, 0xa6, 0x04, 0x95, 0x19, 0x2c, 0xab, 0x94, 0xe1, 0x8d, 0x7b, 0x59, 0x8b, 0xb9, + 0x31, 0xae, 0x3c, 0x25, 0xd3, 0x23, 0xab, 0x8f, 0x95, 0xa3, 0x8b, 0xa5, 0xc1, 0x66, 0x8b, 0x57, 0xe4, 0x88, 0x70, + 0xc9, 0xe0, 0xa1, 0x16, 0x39, 0xf8, 0x12, 0xb3, 0xe5, 0x95, 0x38, 0x3a, 0x01, 0x1d, 0xcc, 0xc0, 0xc3, 0xa9, 0x1c, + 0x72, 0xa7, 0x46, 0x79, 0x51, 0x05, 0xb2, 0x85, 0x5a, 0x97, 0x16, 0x97, 0xa6, 0x85, 0xa4, 0xf2, 0x0b, 0x3c, 0x90, + 0x52, 0xa3, 0xe0, 0xbe, 0xad, 0x06, 0x1b, 0x8e, 0x04, 0x22, 0xeb, 0x3a, 0x48, 0xb9, 0x84, 0x24, 0x0b, 0x24, 0x42, + 0xd9, 0xed, 0x6b, 0x5c, 0xc1, 0xb6, 0x2e, 0xa5, 0xc0, 0x07, 0xfe, 0x3e, 0xbc, 0x9a, 0x92, 0x26, 0xb5, 0xa6, 0x5f, + 0x09, 0x13, 0x85, 0x5a, 0xcf, 0x61, 0x56, 0x65, 0x0f, 0x4c, 0x64, 0x79, 0xfa, 0x0a, 0xcf, 0xc0, 0x95, 0x8d, 0x4d, + 0xc6, 0xbe, 0xee, 0xb3, 0x67, 0xd8, 0xa7, 0x40, 0x90, 0x61, 0xe3, 0xba, 0xcb, 0x18, 0xe0, 0x61, 0x7b, 0x33, 0x86, + 0xf7, 0xef, 0x64, 0xe5, 0x36, 0xf0, 0x9c, 0xb6, 0x34, 0xb1, 0xe1, 0x2a, 0xd8, 0xd8, 0x5e, 0x6b, 0x61, 0x92, 0xa0, + 0x8e, 0x04, 0x7b, 0xbf, 0xa5, 0x84, 0x39, 0x3a, 0xe0, 0x27, 0xc7, 0xb0, 0x83, 0x88, 0x4f, 0x3e, 0x49, 0x14, 0xaa, + 0x34, 0xde, 0xb4, 0xbb, 0x4c, 0xe4, 0xbf, 0xae, 0x9a, 0xf9, 0x88, 0x7a, 0x1f, 0x18, 0xa0, 0x8c, 0x60, 0xc0, 0x5c, + 0x46, 0xa1, 0xd1, 0x36, 0x99, 0x60, 0x9b, 0x73, 0xa2, 0x9a, 0x0b, 0x8d, 0x6e, 0x2f, 0xe1, 0x58, 0x7a, 0x39, 0x71, + 0xed, 0xfc, 0x34, 0xe4, 0x98, 0x57, 0x7e, 0x86, 0xf1, 0xe5, 0x00, 0x7d, 0x1b, 0x6a, 0xfa, 0xf8, 0x6e, 0x7b, 0x12, + 0x44, 0x04, 0x60, 0x02, 0x81, 0x12, 0x09, 0x00, 0xb4, 0x35, 0x9e, 0x03, 0x73, 0x79, 0x9b, 0x13, 0xc5, 0xd7, 0x0e, + 0xce, 0x49, 0x87, 0x48, 0x1a, 0x67, 0x89, 0x93, 0xef, 0xd1, 0xdf, 0x2d, 0x48, 0x6d, 0x30, 0xd5, 0xec, 0x49, 0xfe, + 0x15, 0x1b, 0xa6, 0x2b, 0x6c, 0x08, 0x8e, 0x39, 0x73, 0x68, 0x87, 0xa7, 0x43, 0x28, 0x16, 0x77, 0x86, 0xd1, 0xcb, + 0x13, 0xe4, 0xd3, 0xda, 0x63, 0xcd, 0x3a, 0x2a, 0x35, 0xd5, 0xfa, 0x36, 0x67, 0xc8, 0x4c, 0x6b, 0xa1, 0x8a, 0xaf, + 0x7b, 0x4c, 0x43, 0xb0, 0x2f, 0x4a, 0xcc, 0xc0, 0x11, 0xc6, 0x30, 0x8e, 0xa3, 0xd2, 0x4a, 0x1b, 0x2a, 0x4f, 0xec, + 0x97, 0x83, 0xa6, 0x4c, 0xee, 0x51, 0xaf, 0x06, 0x0a, 0x1d, 0x80, 0xd9, 0xcf, 0xb7, 0x69, 0x23, 0x15, 0x3a, 0x26, + 0x04, 0x34, 0x33, 0x76, 0x30, 0x9f, 0xfb, 0x56, 0xb4, 0x26, 0xee, 0xfa, 0x54, 0x6c, 0x18, 0xf9, 0xd5, 0x32, 0x5d, + 0x03, 0xcb, 0x2c, 0x20, 0x30, 0x0c, 0xa0, 0xbb, 0xde, 0x01, 0x77, 0x65, 0xb0, 0x18, 0x30, 0xd2, 0x55, 0x9f, 0x9b, + 0xcf, 0xb8, 0x9b, 0xb4, 0xbc, 0x0b, 0x49, 0x52, 0x53, 0x30, 0x48, 0xa5, 0x12, 0xe5, 0x3b, 0x47, 0x84, 0xff, 0xf1, + 0x53, 0x5d, 0x5c, 0x04, 0x70, 0x63, 0x91, 0xc3, 0xc0, 0xf0, 0xea, 0xcb, 0x44, 0x4f, 0x8c, 0x85, 0x42, 0x6a, 0xc7, + 0xfa, 0xc7, 0xb5, 0x30, 0x03, 0x12, 0x65, 0xca, 0xba, 0x4f, 0x67, 0xbb, 0xef, 0xb6, 0xc6, 0x3f, 0x19, 0xe2, 0xb5, + 0x4b, 0x8c, 0xfc, 0x9e, 0x18, 0xb0, 0x33, 0x89, 0x6e, 0xde, 0x61, 0x0a, 0xe3, 0x5e, 0xa3, 0x5d, 0x2e, 0x80, 0x3e, + 0x53, 0x67, 0xfb, 0x7b, 0x7a, 0xbf, 0xd5, 0xf4, 0x47 +}; +static const uint8_t AES_GMAC_VECTOR_2_OUT[16] = { 0x67, 0x39, 0x4f, 0x00, 0x04, 0x28, 0xaf, 0xe9, + 0xb4, 0x2e, 0xb5, 0x3c, 0x42, 0x24, 0x86, 0xa3 }; -struct C25519TestVector -{ - uint8_t pub1[64]; - uint8_t priv1[64]; - uint8_t pub2[64]; - uint8_t priv2[64]; - uint8_t agreementSha512[64]; - uint8_t agreementSignedBy1[96]; - uint8_t agreementSignedBy2[96]; +struct C25519TestVector { + uint8_t pub1[64]; + uint8_t priv1[64]; + uint8_t pub2[64]; + uint8_t priv2[64]; + uint8_t agreementSha512[64]; + uint8_t agreementSignedBy1[96]; + uint8_t agreementSignedBy2[96]; }; #define ZT_NUM_C25519_TEST_VECTORS 32 static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = { - {{0xa1, 0xfc, 0x7a, 0xb4, 0x6d, 0xdf, 0x7d, 0xcf, 0xe7, 0xec, 0x75, 0xe5, 0xfa, 0xdd, 0x11, 0xcb, 0xcc, 0x37, 0xf8, 0x84, 0x5d, 0x1c, 0x92, 0x4e, 0x09, 0x89, 0x65, 0xfc, 0xd8, 0xe9, 0x5a, 0x30, 0xda, 0xe4, 0x86, 0xa3, 0x35, 0xb4, 0x19, 0x0c, 0xbc, 0x7b, 0xcb, 0x3e, 0xb9, 0x4c, 0xbd, 0x16, 0xe8, 0x3d, 0x13, 0x2b, 0xc9, 0xc3, 0x39, 0xea, 0xf1, 0x42, 0xe7, 0x6f, 0x69, 0x78, 0x9a, 0xb7}, {0xe5, 0xf3, 0x7b, 0xd4, 0x0e, 0xc9, 0xdc, 0x77, 0x50, 0x86, 0xdc, 0xf4, 0x2e, 0xbc, 0xdb, 0x27, 0xf0, 0x73, 0xd4, 0x58, 0x73, 0xc4, 0x4b, 0x71, 0x8b, 0x3c, 0xc5, 0x4f, 0xa8, 0x7c, 0xa4, 0x84, 0xd9, 0x96, 0x23, 0x73, 0xb4, 0x03, 0x16, 0xbf, 0x1e, 0xa1, 0x2d, 0xd8, 0xc4, 0x8a, 0xe7, 0x82, 0x10, 0xda, 0xc9, 0xe5, 0x45, 0x9b, 0x01, 0xdc, 0x73, 0xa6, 0xc9, 0x17, 0xa8, 0x15, 0x31, 0x6d}, {0x3e, 0x49, 0xa4, 0x0e, 0x3a, 0xaf, 0xa3, 0x07, 0x3d, 0xf7, 0x2a, 0xec, 0x43, 0xb1, 0xd4, 0x09, 0x1a, 0xcb, 0x8e, 0x92, 0xf9, 0x65, 0x95, 0x04, 0x6d, 0x2d, 0x9b, 0x34, 0xa3, 0xbf, 0x51, 0x00, 0xe2, 0xee, 0x23, 0xf5, 0x28, 0x0a, 0xa9, 0xb1, 0x57, 0x0b, 0x96, 0x56, 0x62, 0xba, 0x12, 0x94, 0xaf, 0xc6, 0x5f, 0xb5, 0x61, 0x43, 0x0f, 0xde, 0x0b, 0xab, 0xfa, 0x4f, 0xfe, 0xc5, 0xe7, 0x18}, {0x00, 0x4d, 0x41, 0x8d, 0xe4, 0x69, 0x23, 0xae, 0x98, 0xc4, 0x3e, 0x77, 0x0f, 0x1d, 0x94, 0x5d, 0x29, 0x3e, 0x94, 0x5a, 0x38, 0x39, 0x20, 0x0f, 0xd3, 0x6f, 0x76, 0xa2, 0x29, 0x02, 0x03, 0xcb, 0x0b, 0x7f, 0x4f, 0x1a, 0x29, 0x51, 0x13, 0x33, 0x7c, 0x99, 0xb3, 0x81, 0x82, 0x39, 0x44, 0x05, 0x97, 0xfb, 0x0d, 0xf2, 0x93, 0xa2, 0x40, 0x94, 0xf4, 0xff, 0x5d, 0x09, 0x61, 0xe4, 0x5f, 0x76}, {0xab, 0xce, 0xd2, 0x24, 0xe8, 0x93, 0xb0, 0xe7, 0x72, 0x14, 0xdc, 0xbb, 0x7d, 0x0f, 0xd8, 0x94, 0x16, 0x9e, 0xb5, 0x7f, 0xd7, 0x19, 0x5f, 0x3e, 0x2d, 0x45, 0xd5, 0xf7, 0x90, 0x0b, 0x3e, 0x05, 0x18, 0x2e, 0x2b, 0xf4, 0xfa, 0xd4, 0xec, 0x62, 0x4a, 0x4f, 0x48, 0x50, 0xaf, 0x1c, 0xe8, 0x9f, 0x1a, 0xe1, 0x3d, 0x70, 0x49, 0x00, 0xa7, 0xe3, 0x5b, 0x1e, 0xa1, 0x9b, 0x68, 0x1e, 0xa1, 0x73}, {0xed, 0xb6, 0xd0, 0xf0, 0x06, 0x6e, 0x33, 0x9c, 0x86, 0xfb, 0xe8, 0xc3, 0x6c, 0x8d, 0xde, 0xdd, 0xa6, 0xa0, 0x2d, 0xb9, 0x07, 0x29, 0xa3, 0x13, 0xbb, 0xa4, 0xba, 0xec, 0x48, 0xc8, 0xf4, 0x56, 0x82, 0x79, 0xe2, 0xb1, 0xd3, 0x3d, 0x83, 0x9f, 0x10, 0xe8, 0x52, 0xe6, 0x8b, 0x1c, 0x33, 0x9e, 0x2b, 0xd2, 0xdb, 0x62, 0x1c, 0x56, 0xfd, 0x50, 0x40, 0x77, 0x81, 0xab, 0x21, 0x67, 0x3e, 0x09, 0x4f, 0xf2, 0x51, 0xac, 0x7d, 0xe7, 0xd1, 0x5d, 0x4b, 0xe2, 0x08, 0xc6, 0x3f, 0x6a, 0x4d, 0xc8, 0x5d, 0x74, 0xf6, 0x3b, 0xec, 0x8e, 0xc6, 0x0c, 0x32, 0x27, 0x2f, 0x9c, 0x09, 0x48, 0x59, 0x10}, {0x23, 0x0f, 0xa3, 0xe2, 0x69, 0xce, 0xb9, 0xb9, 0xd1, 0x1c, 0x4e, 0xab, 0x63, 0xc9, 0x2e, 0x1e, 0x7e, 0xa2, 0xa2, 0xa0, 0x49, 0x2e, 0x78, 0xe4, 0x8a, 0x02, 0x3b, 0xa7, 0xab, 0x1f, 0xd4, 0xce, 0x05, 0xe2, 0x80, 0x09, 0x09, 0x3c, 0x61, 0xc7, 0x10, 0x3a, 0x9c, 0xf4, 0x95, 0xac, 0x89, 0x6f, 0x23, 0xb3, 0x09, 0xe2, 0x24, 0x3f, 0xf6, 0x96, 0x02, 0x36, 0x41, 0x16, 0x32, 0xe1, 0x66, 0x05, 0x4f, 0xf2, 0x51, 0xac, 0x7d, 0xe7, 0xd1, 0x5d, 0x4b, 0xe2, 0x08, 0xc6, 0x3f, 0x6a, 0x4d, 0xc8, 0x5d, 0x74, 0xf6, 0x3b, 0xec, 0x8e, 0xc6, 0x0c, 0x32, 0x27, 0x2f, 0x9c, 0x09, 0x48, 0x59, 0x10}}, - {{0xfd, 0x81, 0x14, 0xf1, 0x67, 0x07, 0x44, 0xbb, 0x93, 0x84, 0xa2, 0xdc, 0x36, 0xdc, 0xcc, 0xb3, 0x9e, 0x82, 0xd4, 0x8b, 0x42, 0x56, 0xfb, 0xf2, 0x6e, 0x83, 0x3b, 0x16, 0x2c, 0x29, 0xfb, 0x39, 0x29, 0x48, 0x85, 0xe3, 0xe3, 0xf7, 0xe7, 0x80, 0x49, 0xd3, 0x01, 0x30, 0x5a, 0x2c, 0x3f, 0x4c, 0xea, 0x13, 0xeb, 0xda, 0xf4, 0x56, 0x75, 0x8d, 0x50, 0x1e, 0x19, 0x2d, 0x29, 0x2b, 0xfb, 0xdb}, {0x85, 0x34, 0x4d, 0xf7, 0x39, 0xbf, 0x98, 0x79, 0x8c, 0x98, 0xeb, 0x8d, 0x61, 0x27, 0xec, 0x87, 0x56, 0xcd, 0xd0, 0xa6, 0x55, 0x77, 0xee, 0xf0, 0x20, 0xd0, 0x59, 0x39, 0x95, 0xab, 0x29, 0x82, 0x8e, 0x61, 0xf8, 0xad, 0xed, 0xb6, 0x27, 0xc3, 0xd8, 0x16, 0xce, 0x67, 0x78, 0xe2, 0x04, 0x4b, 0x0c, 0x2d, 0x2f, 0xc3, 0x24, 0x72, 0xbc, 0x53, 0xbd, 0xfe, 0x39, 0x23, 0xd4, 0xaf, 0x27, 0x84}, {0x11, 0xbe, 0x5f, 0x5a, 0x73, 0xe7, 0x42, 0xef, 0xff, 0x3c, 0x47, 0x6a, 0x0e, 0x6b, 0x9e, 0x96, 0x21, 0xa3, 0xdf, 0x49, 0xe9, 0x3f, 0x40, 0xfc, 0xab, 0xb3, 0x66, 0xd3, 0x3d, 0xfa, 0x02, 0x29, 0xf3, 0x43, 0x45, 0x3c, 0x70, 0xa3, 0x5d, 0x39, 0xf7, 0xc0, 0x6a, 0xcd, 0xfa, 0x1d, 0xbe, 0x3b, 0x91, 0x41, 0xe4, 0xb0, 0x60, 0xc0, 0x22, 0xf7, 0x2c, 0x11, 0x2b, 0x1c, 0x5f, 0x24, 0xef, 0x53}, {0xfd, 0x3f, 0x09, 0x06, 0xc9, 0x39, 0x8d, 0x48, 0xfa, 0x6b, 0xc9, 0x80, 0xbf, 0xf6, 0xd6, 0x76, 0xb3, 0x62, 0x70, 0x88, 0x4f, 0xde, 0xde, 0xb9, 0xb4, 0xf0, 0xce, 0xf3, 0x74, 0x0d, 0xea, 0x00, 0x9e, 0x9c, 0x29, 0xe1, 0xa2, 0x1b, 0xbd, 0xb5, 0x83, 0xcc, 0x12, 0xd8, 0x48, 0x08, 0x5b, 0xe5, 0xd6, 0xf9, 0x11, 0x5c, 0xe0, 0xd9, 0xc3, 0x3c, 0x26, 0xbd, 0x69, 0x9f, 0x5c, 0x6f, 0x0c, 0x6f}, {0xca, 0xd4, 0x76, 0x32, 0x8b, 0xbe, 0x0c, 0x65, 0x75, 0x43, 0x73, 0xc2, 0xf2, 0xfd, 0x7f, 0xeb, 0xe4, 0x62, 0xc5, 0x0d, 0x0f, 0xf9, 0x01, 0xc8, 0xb9, 0xfa, 0xca, 0xb4, 0x12, 0x1c, 0xb4, 0xac, 0x0e, 0x5f, 0x18, 0xfc, 0x0c, 0x7f, 0x2a, 0x55, 0xc5, 0xfd, 0x4d, 0x83, 0xb2, 0x02, 0x31, 0x6a, 0x3f, 0x14, 0xee, 0x9d, 0x11, 0xa8, 0x06, 0xad, 0xeb, 0x93, 0x19, 0x79, 0xb1, 0xf2, 0x78, 0x05}, {0x85, 0xe6, 0xe2, 0xf2, 0x96, 0xe7, 0xa2, 0x8b, 0x7e, 0x36, 0xbd, 0x7b, 0xf4, 0x28, 0x6a, 0xd7, 0xbc, 0x2a, 0x6a, 0x59, 0xfd, 0xc0, 0xc8, 0x3d, 0x50, 0x0f, 0x0c, 0x2b, 0x12, 0x3a, 0x75, 0xc7, 0x56, 0xbb, 0x7f, 0x7d, 0x4e, 0xd4, 0x03, 0xb8, 0x7b, 0xde, 0xde, 0x99, 0x65, 0x9e, 0xc4, 0xa6, 0x6e, 0xfe, 0x00, 0x88, 0xeb, 0x9d, 0xa4, 0xa9, 0x9d, 0x37, 0xc9, 0x4a, 0xcf, 0x69, 0xc4, 0x01, 0xba, 0xa8, 0xce, 0xeb, 0x72, 0xcb, 0x64, 0x8b, 0x9f, 0xc1, 0x1f, 0x9a, 0x9e, 0x99, 0xcc, 0x39, 0xec, 0xd9, 0xbb, 0xd9, 0xce, 0xc2, 0x74, 0x6f, 0xd0, 0x2a, 0xb9, 0xc6, 0xe3, 0xf5, 0xe7, 0xf4}, {0xb1, 0x39, 0x50, 0xb1, 0x1a, 0x08, 0x42, 0x2b, 0xdd, 0x6d, 0x20, 0x9f, 0x0f, 0x37, 0xba, 0x69, 0x97, 0x21, 0x30, 0x7a, 0x71, 0x2f, 0xce, 0x98, 0x09, 0x04, 0xa2, 0x98, 0x6a, 0xed, 0x02, 0x1d, 0x5d, 0x30, 0x8f, 0x03, 0x47, 0x6b, 0x89, 0xfd, 0xf7, 0x1a, 0xca, 0x46, 0x6f, 0x51, 0x69, 0x9a, 0x2b, 0x18, 0x77, 0xe4, 0xad, 0x0d, 0x7a, 0x66, 0xd2, 0x2c, 0x28, 0xa0, 0xd3, 0x0a, 0x99, 0x0d, 0xba, 0xa8, 0xce, 0xeb, 0x72, 0xcb, 0x64, 0x8b, 0x9f, 0xc1, 0x1f, 0x9a, 0x9e, 0x99, 0xcc, 0x39, 0xec, 0xd9, 0xbb, 0xd9, 0xce, 0xc2, 0x74, 0x6f, 0xd0, 0x2a, 0xb9, 0xc6, 0xe3, 0xf5, 0xe7, 0xf4}}, - {{0x02, 0x3a, 0x7e, 0x0c, 0x6d, 0x96, 0x3c, 0x5d, 0x44, 0x56, 0x5d, 0xc1, 0x49, 0x94, 0x35, 0x12, 0x9d, 0xff, 0x8a, 0x5d, 0x91, 0x74, 0xa8, 0x15, 0xee, 0x5d, 0x1e, 0x72, 0xbe, 0x86, 0x15, 0x68, 0xe7, 0x36, 0xa2, 0x4a, 0xb8, 0xa2, 0xa4, 0x4c, 0xd8, 0x95, 0xe3, 0xc7, 0xbb, 0x32, 0x21, 0x90, 0x64, 0x52, 0x32, 0xeb, 0x26, 0xd3, 0x4f, 0xf0, 0x8e, 0x27, 0x40, 0xea, 0xed, 0xdb, 0xf5, 0xc4}, {0x76, 0x99, 0x64, 0x70, 0xf4, 0x50, 0xc8, 0xcc, 0x4a, 0x5a, 0xa5, 0x0f, 0xeb, 0x2d, 0xc7, 0x0e, 0x73, 0xd0, 0x65, 0x7d, 0xc3, 0xce, 0x73, 0x03, 0x20, 0x2f, 0xad, 0x65, 0xfd, 0x12, 0xe4, 0x7f, 0xfd, 0x45, 0x3a, 0x6e, 0xc5, 0x9a, 0x06, 0x67, 0x0e, 0xa6, 0x7b, 0x21, 0x49, 0x2d, 0x01, 0x1b, 0x8e, 0x03, 0x6e, 0x10, 0x08, 0x0c, 0x68, 0xd9, 0x60, 0x47, 0xa4, 0xe2, 0x52, 0xfd, 0x3c, 0xf4}, {0xa3, 0xe2, 0x5f, 0x16, 0x39, 0x78, 0x96, 0xf7, 0x47, 0x6f, 0x93, 0x5d, 0x27, 0x7b, 0x58, 0xe0, 0xc5, 0xdb, 0x71, 0x7d, 0xa9, 0x6f, 0xf8, 0x8b, 0x69, 0xdd, 0x50, 0xea, 0x91, 0x0d, 0x66, 0x77, 0xaf, 0x8f, 0xd5, 0x9f, 0x8a, 0x26, 0x69, 0x4c, 0x64, 0x37, 0x62, 0x81, 0x6f, 0x05, 0x9a, 0x08, 0x0d, 0xe1, 0x69, 0x24, 0x77, 0x3f, 0x50, 0xb2, 0x49, 0x4d, 0x93, 0xef, 0x2e, 0x87, 0xff, 0xde}, {0xb3, 0x32, 0xe2, 0x67, 0x79, 0x32, 0x5f, 0x64, 0x47, 0x49, 0x1c, 0xd3, 0x8f, 0x95, 0x44, 0xfd, 0x4c, 0x7e, 0xbf, 0x6b, 0xb7, 0xaf, 0x2c, 0xdd, 0x8f, 0xa5, 0xd8, 0x2f, 0xbf, 0xa0, 0x8a, 0x6b, 0x58, 0x25, 0xc9, 0x12, 0x23, 0x6f, 0xe6, 0x05, 0xa8, 0xd0, 0x68, 0x6e, 0x0c, 0xee, 0x70, 0xe4, 0xa3, 0x86, 0x51, 0x04, 0x6d, 0xca, 0xd5, 0xed, 0xcf, 0x74, 0x1d, 0x60, 0x9e, 0x86, 0x2d, 0x05}, {0x91, 0xf4, 0x5f, 0x4a, 0xcb, 0xd8, 0xfd, 0x5f, 0xb9, 0x3d, 0x04, 0xb8, 0xec, 0x35, 0x85, 0x4f, 0x58, 0x20, 0xd1, 0x1f, 0x47, 0xc4, 0xf4, 0xcb, 0x21, 0x4e, 0x9a, 0xf1, 0x6e, 0xbf, 0xe3, 0xd3, 0x62, 0xe3, 0x82, 0xf6, 0xba, 0xa8, 0xdf, 0x92, 0xe2, 0x3c, 0xe5, 0xf0, 0x16, 0x8a, 0xeb, 0xa4, 0xbb, 0xc7, 0x81, 0xaf, 0x15, 0x19, 0x87, 0x5f, 0xb7, 0xe0, 0x4c, 0x12, 0xff, 0x2c, 0xa9, 0xc8}, {0xaf, 0x85, 0xe0, 0x36, 0x43, 0xdf, 0x41, 0x17, 0xda, 0xde, 0x5e, 0xb6, 0x33, 0xd0, 0xce, 0x62, 0x70, 0x5f, 0x85, 0x24, 0x6c, 0x3e, 0x1b, 0xe1, 0x52, 0xc1, 0x9b, 0x1c, 0xcd, 0x61, 0x80, 0x9c, 0xa0, 0xe8, 0x18, 0xee, 0x40, 0x91, 0x93, 0x82, 0xdb, 0x33, 0x44, 0xff, 0xd4, 0xf6, 0x6f, 0x5d, 0xf0, 0x0e, 0x92, 0x92, 0x81, 0x55, 0x46, 0x06, 0xac, 0x58, 0x81, 0x3b, 0x04, 0xc7, 0xf7, 0x0d, 0xd2, 0x0c, 0x08, 0x6d, 0x46, 0xdb, 0x43, 0x28, 0x31, 0xd8, 0xcd, 0x87, 0x50, 0xbb, 0xd3, 0x07, 0xf5, 0x72, 0x0b, 0x15, 0x7c, 0x16, 0xab, 0x03, 0xd9, 0x4b, 0x07, 0x38, 0x97, 0xe8, 0xd6, 0xb5}, {0x93, 0xff, 0x6d, 0xc3, 0x62, 0xf7, 0xcc, 0x20, 0x95, 0xc2, 0x2f, 0x7d, 0x1d, 0x9b, 0xd1, 0x63, 0xfc, 0x61, 0x47, 0xb3, 0x22, 0x0f, 0xca, 0xb0, 0x16, 0xcf, 0x29, 0x53, 0x46, 0x97, 0xb1, 0x36, 0x46, 0xac, 0x48, 0x13, 0x92, 0xe4, 0x46, 0x68, 0xcf, 0x09, 0x4e, 0xfa, 0x59, 0x45, 0x24, 0x08, 0xdb, 0xb4, 0x6f, 0x20, 0x55, 0x12, 0xd9, 0x75, 0x9d, 0x8e, 0x0b, 0xf8, 0x63, 0xe0, 0xf9, 0x01, 0xd2, 0x0c, 0x08, 0x6d, 0x46, 0xdb, 0x43, 0x28, 0x31, 0xd8, 0xcd, 0x87, 0x50, 0xbb, 0xd3, 0x07, 0xf5, 0x72, 0x0b, 0x15, 0x7c, 0x16, 0xab, 0x03, 0xd9, 0x4b, 0x07, 0x38, 0x97, 0xe8, 0xd6, 0xb5}}, - {{0x14, 0x35, 0xa6, 0x7d, 0xc1, 0xb5, 0x71, 0xca, 0x42, 0x50, 0x90, 0xa7, 0x72, 0x85, 0xbe, 0x78, 0x7a, 0x5f, 0x83, 0x1e, 0xbe, 0xef, 0x6a, 0xbe, 0x48, 0xc5, 0x68, 0x14, 0x0c, 0xf7, 0x44, 0x5c, 0x2e, 0xfd, 0x1b, 0xcc, 0xee, 0x09, 0x23, 0x82, 0x31, 0xad, 0xaf, 0x4b, 0x73, 0x9c, 0xf2, 0x88, 0x3c, 0xf3, 0xb5, 0x43, 0x8b, 0x53, 0xf9, 0xac, 0x17, 0x86, 0x1c, 0xc2, 0x53, 0x43, 0xec, 0x03}, {0x7b, 0x36, 0x6c, 0xcc, 0xb5, 0xb2, 0x23, 0x3d, 0x7c, 0xe5, 0xe7, 0xcf, 0x06, 0xe2, 0x32, 0x0b, 0xc5, 0x3b, 0x7f, 0x86, 0x40, 0xfc, 0xaf, 0xba, 0x94, 0xe0, 0x88, 0x58, 0x5b, 0xac, 0xe8, 0xc3, 0xe8, 0xc3, 0xdf, 0xc4, 0x45, 0x29, 0xe8, 0xf0, 0x1c, 0x10, 0x0d, 0x50, 0x81, 0x29, 0x30, 0xa8, 0x27, 0xb5, 0x3e, 0xb8, 0x25, 0xf1, 0x17, 0x30, 0xc6, 0x05, 0xe3, 0x3e, 0x45, 0x38, 0xa8, 0x3c}, {0xce, 0xd9, 0x45, 0x28, 0xb0, 0xce, 0xa5, 0x47, 0xa8, 0x29, 0x32, 0x76, 0x99, 0x73, 0x8d, 0x74, 0xf9, 0xed, 0x0a, 0xd0, 0xf1, 0xd8, 0x7e, 0x44, 0x63, 0x9e, 0x9a, 0xcf, 0x7c, 0x35, 0x8a, 0x29, 0xbb, 0x71, 0x66, 0x8d, 0xa7, 0xfc, 0x05, 0x3d, 0xd4, 0x4b, 0x65, 0x20, 0xf5, 0xa4, 0x64, 0xd8, 0x9d, 0x16, 0x80, 0x9c, 0xb2, 0x3c, 0x3e, 0xd4, 0x9d, 0x09, 0x88, 0x8e, 0xbb, 0x58, 0xf8, 0x77}, {0xe1, 0x29, 0xb3, 0x16, 0xe6, 0xa0, 0xdb, 0x64, 0x08, 0x36, 0xdc, 0x33, 0xad, 0x8b, 0x30, 0x26, 0x17, 0x56, 0xd7, 0x34, 0x17, 0xd1, 0xdd, 0x23, 0x38, 0x58, 0x25, 0x01, 0x42, 0x5a, 0x9d, 0x18, 0x3e, 0xac, 0x31, 0xfa, 0x43, 0x28, 0xc4, 0x65, 0xfb, 0x30, 0x2f, 0x8c, 0x16, 0x52, 0x32, 0x1b, 0x19, 0xb7, 0x31, 0xf6, 0x67, 0xa7, 0xd8, 0xed, 0x9a, 0xa3, 0x95, 0x01, 0xd7, 0xb9, 0xe7, 0xcc}, {0x81, 0x2d, 0x11, 0xa9, 0x11, 0xf1, 0x22, 0xe2, 0x67, 0x70, 0xc4, 0xba, 0x34, 0xa1, 0x75, 0x8c, 0xf6, 0x0c, 0x63, 0xe7, 0x01, 0x3c, 0x64, 0x6c, 0xe8, 0xd0, 0xf8, 0x8e, 0x88, 0xdf, 0x5c, 0x61, 0x68, 0x5d, 0x1f, 0xeb, 0x83, 0x1f, 0x40, 0xb8, 0xa8, 0x56, 0x57, 0x26, 0x81, 0x2c, 0xa3, 0x0e, 0x48, 0x4c, 0x45, 0x4d, 0x0d, 0x3d, 0x6e, 0x99, 0x52, 0xbd, 0x0b, 0xd8, 0x05, 0xc5, 0xf9, 0x61}, {0x92, 0x45, 0xbe, 0xe6, 0xb4, 0x7a, 0xfa, 0x28, 0xd4, 0x5b, 0x6b, 0x17, 0xc6, 0x13, 0x61, 0x5d, 0x5f, 0xd7, 0x90, 0xbb, 0x89, 0x35, 0x7a, 0x02, 0x50, 0x57, 0x56, 0x5f, 0x19, 0xb5, 0xb6, 0xc5, 0x77, 0x1e, 0x1b, 0xc0, 0xd7, 0x7a, 0x29, 0xbd, 0xe7, 0x24, 0x01, 0x2d, 0x37, 0xc0, 0x38, 0x6f, 0xc8, 0x35, 0xa1, 0x1b, 0xe0, 0xea, 0x16, 0xad, 0xbc, 0xdc, 0xd4, 0x8d, 0x4e, 0x71, 0xdb, 0x05, 0x9e, 0xb5, 0x53, 0x6b, 0x5c, 0xf1, 0x7d, 0x15, 0x8b, 0xd7, 0xc7, 0x8b, 0x89, 0x9d, 0xfd, 0x28, 0x7c, 0xa1, 0x31, 0xe2, 0xf0, 0x2c, 0x3a, 0x8d, 0x0e, 0x23, 0x85, 0x4e, 0xf0, 0xd1, 0xc0, 0x83}, {0x7b, 0x88, 0xeb, 0x45, 0x1c, 0x7f, 0xfd, 0xbe, 0xba, 0xac, 0x53, 0x28, 0x59, 0xe8, 0xad, 0x28, 0xf1, 0x97, 0x2d, 0x6c, 0x31, 0xa6, 0xae, 0x47, 0x10, 0x69, 0x68, 0x55, 0xa6, 0x9c, 0x03, 0x62, 0xb7, 0x2f, 0x31, 0x46, 0x2a, 0x2b, 0x98, 0xdd, 0xe9, 0xf9, 0xfe, 0x77, 0x71, 0x41, 0x54, 0xf8, 0x59, 0x02, 0x7a, 0xe3, 0x45, 0x67, 0xb6, 0xf7, 0x94, 0x31, 0x3e, 0x62, 0x62, 0x2a, 0xf9, 0x0a, 0x9e, 0xb5, 0x53, 0x6b, 0x5c, 0xf1, 0x7d, 0x15, 0x8b, 0xd7, 0xc7, 0x8b, 0x89, 0x9d, 0xfd, 0x28, 0x7c, 0xa1, 0x31, 0xe2, 0xf0, 0x2c, 0x3a, 0x8d, 0x0e, 0x23, 0x85, 0x4e, 0xf0, 0xd1, 0xc0, 0x83}}, - {{0x27, 0x4d, 0x84, 0x08, 0x95, 0x84, 0xc8, 0xeb, 0x1c, 0x9a, 0x0f, 0xca, 0x09, 0x6f, 0x48, 0x8b, 0x2b, 0x06, 0xa0, 0xae, 0xf2, 0xe3, 0x8a, 0xfe, 0xd7, 0x52, 0x4b, 0xf2, 0xc6, 0x7c, 0xc1, 0x55, 0x87, 0x2e, 0x5a, 0xb4, 0xc2, 0x43, 0x0a, 0x0d, 0xd0, 0x00, 0xa8, 0xe1, 0x46, 0x68, 0x79, 0xd8, 0x8c, 0x01, 0x36, 0xb7, 0x5a, 0x61, 0x04, 0xe9, 0x7e, 0xbb, 0xc9, 0xee, 0xaa, 0x12, 0x13, 0xda}, {0x78, 0x66, 0xd0, 0xa2, 0x50, 0x82, 0x8d, 0xb0, 0xa0, 0x20, 0xac, 0xa4, 0xb6, 0xa0, 0x31, 0xf7, 0x7d, 0x93, 0x37, 0x67, 0xbb, 0x60, 0xa2, 0x1e, 0x36, 0xce, 0x3d, 0x48, 0x1d, 0x79, 0x99, 0xa5, 0x19, 0xd8, 0x89, 0x1b, 0xcb, 0x14, 0x87, 0xb7, 0x62, 0xfd, 0xd2, 0xef, 0xbb, 0x13, 0x41, 0x4d, 0xf1, 0x77, 0x5c, 0x7f, 0x6c, 0x3b, 0x94, 0x7d, 0xb4, 0xba, 0x87, 0x3e, 0xc8, 0xe1, 0x3c, 0x0a}, {0xd9, 0x9e, 0x14, 0x89, 0xd6, 0xf8, 0x49, 0xa2, 0xe2, 0x19, 0xfe, 0x94, 0xaa, 0xf7, 0x35, 0xf9, 0x4a, 0xf8, 0xf3, 0x18, 0x68, 0x96, 0x47, 0xc6, 0x23, 0x7c, 0xb0, 0x53, 0xcb, 0xd8, 0x90, 0x31, 0xb7, 0x50, 0x0e, 0x06, 0xc3, 0x84, 0x75, 0xf1, 0xac, 0x16, 0x4d, 0xc1, 0xbe, 0xf1, 0x80, 0x33, 0x47, 0x56, 0x6f, 0x33, 0x94, 0x5c, 0x81, 0x03, 0x4c, 0x2f, 0x6d, 0xac, 0x73, 0xba, 0x91, 0x3c}, {0x2f, 0xa9, 0xb6, 0xe8, 0x73, 0xe2, 0xef, 0x6d, 0x6d, 0xd7, 0x2e, 0xa0, 0x51, 0x61, 0x24, 0x81, 0x8c, 0xa8, 0x47, 0x40, 0xe1, 0xc7, 0x75, 0x79, 0xc8, 0xec, 0xb2, 0x23, 0x41, 0xad, 0x61, 0x3b, 0xea, 0x8a, 0xdf, 0x63, 0xed, 0xe1, 0x8e, 0x50, 0x70, 0x6e, 0x86, 0xed, 0xb0, 0xba, 0x27, 0x48, 0x8e, 0xb9, 0x63, 0x39, 0x78, 0x58, 0x4f, 0x1e, 0xbc, 0x45, 0xf3, 0xf2, 0x3a, 0x73, 0x9b, 0x8c}, {0xad, 0x42, 0xc5, 0x84, 0xca, 0xe1, 0xe1, 0x23, 0x2a, 0x73, 0x15, 0x3c, 0x9a, 0xfe, 0x85, 0x8d, 0xa3, 0x2c, 0xcf, 0x46, 0x8d, 0x7f, 0x1c, 0x61, 0xd7, 0x0e, 0xb1, 0xa6, 0xb4, 0xae, 0xab, 0x63, 0xc4, 0x0e, 0xf2, 0xa0, 0x5d, 0xa6, 0xf3, 0x5d, 0x35, 0x41, 0xea, 0x03, 0x91, 0xb1, 0x3a, 0x07, 0xe6, 0xed, 0x6c, 0x8c, 0xcb, 0x75, 0x27, 0xf1, 0x26, 0x58, 0xf0, 0x62, 0x57, 0xe4, 0x33, 0x00}, {0x1f, 0xed, 0x53, 0xc6, 0xef, 0x38, 0x26, 0xa4, 0x18, 0x88, 0x8f, 0x5c, 0x49, 0x1c, 0x15, 0x7d, 0x77, 0x90, 0x06, 0x39, 0xe0, 0x7c, 0x25, 0xed, 0x79, 0x05, 0x66, 0xe0, 0x5e, 0x94, 0xe3, 0x46, 0x6f, 0x96, 0xd8, 0xc1, 0x11, 0xa4, 0x11, 0x6f, 0x78, 0x42, 0x8e, 0x89, 0xc7, 0xc3, 0xed, 0xd2, 0x9e, 0x68, 0x47, 0x79, 0x89, 0x23, 0x70, 0x14, 0x21, 0x60, 0x2d, 0xfe, 0x37, 0x4b, 0xc8, 0x0a, 0x16, 0x73, 0x7c, 0xc4, 0x55, 0x3f, 0x25, 0x04, 0x08, 0x75, 0x74, 0x68, 0xbc, 0xe4, 0x3a, 0xae, 0x4c, 0x0e, 0xd2, 0x85, 0xa1, 0xbc, 0x81, 0xc0, 0xc9, 0xfe, 0x9a, 0x44, 0x7b, 0x83, 0xdf, 0xc7}, {0x27, 0x77, 0x97, 0x84, 0x0f, 0x2d, 0x8d, 0x33, 0xb8, 0x4e, 0xdb, 0x8b, 0xea, 0x58, 0x52, 0x88, 0x95, 0x88, 0x55, 0x5f, 0xb8, 0xc4, 0xc9, 0xd6, 0x1f, 0x1e, 0xee, 0x60, 0xb5, 0xeb, 0x78, 0x72, 0xb5, 0xe5, 0x22, 0x2b, 0x7f, 0x5e, 0xc7, 0x9b, 0x29, 0x55, 0x8e, 0x2a, 0xfc, 0x65, 0x55, 0x4a, 0x02, 0xad, 0x64, 0x06, 0xd4, 0x25, 0xe1, 0x96, 0x6f, 0xee, 0x96, 0xcd, 0x29, 0xc6, 0x64, 0x00, 0x16, 0x73, 0x7c, 0xc4, 0x55, 0x3f, 0x25, 0x04, 0x08, 0x75, 0x74, 0x68, 0xbc, 0xe4, 0x3a, 0xae, 0x4c, 0x0e, 0xd2, 0x85, 0xa1, 0xbc, 0x81, 0xc0, 0xc9, 0xfe, 0x9a, 0x44, 0x7b, 0x83, 0xdf, 0xc7}}, - {{0x5e, 0xc5, 0x5b, 0x9c, 0xdb, 0x14, 0x05, 0x18, 0x6b, 0xe2, 0x1d, 0x16, 0x77, 0x22, 0x0e, 0xd2, 0xe4, 0x57, 0x82, 0x6e, 0x5b, 0xc5, 0x6a, 0xb9, 0x34, 0x20, 0xdb, 0x72, 0xe2, 0xe1, 0xeb, 0x1b, 0x34, 0x00, 0x04, 0xbf, 0x83, 0xf6, 0x4f, 0x12, 0x45, 0x08, 0xf0, 0x95, 0x2a, 0xdc, 0x3a, 0x14, 0xb3, 0x29, 0x0b, 0x99, 0xcd, 0x73, 0x31, 0xbd, 0x04, 0xbb, 0x49, 0x1c, 0xde, 0xcf, 0x09, 0x9e}, {0x15, 0x80, 0x3e, 0x2a, 0xfb, 0xc0, 0x8d, 0x62, 0x19, 0x27, 0x83, 0x04, 0xcc, 0xf5, 0xd1, 0xbb, 0x40, 0x41, 0xbe, 0x93, 0x59, 0x6e, 0x27, 0x6d, 0x95, 0x24, 0x0a, 0x07, 0x27, 0x86, 0x10, 0x75, 0xf7, 0x0a, 0x11, 0xfc, 0x53, 0xd0, 0x4c, 0x15, 0xf8, 0x6e, 0x22, 0x3f, 0xeb, 0x12, 0x97, 0x8a, 0x3d, 0x69, 0xd8, 0x96, 0xc9, 0x53, 0x10, 0x9c, 0x02, 0x95, 0xe4, 0xd3, 0x1a, 0xd5, 0x43, 0x82}, {0x40, 0x09, 0x2c, 0x17, 0x7e, 0xba, 0xce, 0x1f, 0xfc, 0xc1, 0x8e, 0xc3, 0x1c, 0xa2, 0x34, 0x52, 0x78, 0x16, 0x23, 0x71, 0x82, 0x40, 0xf8, 0x6d, 0x67, 0x65, 0x67, 0x50, 0x53, 0xd9, 0xc8, 0x5e, 0x7e, 0x8a, 0x98, 0xa3, 0xc6, 0x2a, 0x4d, 0x27, 0xf3, 0xb9, 0xbb, 0xae, 0x43, 0x29, 0x6e, 0x02, 0x1c, 0xe9, 0x01, 0xd6, 0xcd, 0xd8, 0x91, 0x44, 0x95, 0x2b, 0x9e, 0xa5, 0x4f, 0xd0, 0x00, 0xb9}, {0x3a, 0xe8, 0x3d, 0xb3, 0x32, 0xdc, 0xc2, 0xc8, 0xe3, 0x36, 0x2f, 0xc9, 0x30, 0x3a, 0xc0, 0x76, 0x56, 0xd3, 0x0b, 0x06, 0xbe, 0x8f, 0xe7, 0xf1, 0x66, 0x61, 0x25, 0x42, 0x28, 0xdc, 0x08, 0x81, 0x84, 0x3a, 0x57, 0x96, 0x27, 0xa6, 0xcf, 0xd6, 0x8f, 0x35, 0xa2, 0xc3, 0x76, 0x86, 0x4f, 0xcf, 0x5f, 0xa1, 0x85, 0x28, 0x4f, 0x4a, 0x3a, 0xbb, 0x5c, 0x25, 0x4b, 0xcc, 0x46, 0xfe, 0xf2, 0x04}, {0x62, 0xc8, 0xa2, 0x0a, 0x59, 0xb8, 0x97, 0xd2, 0x68, 0x94, 0x00, 0x3b, 0x01, 0xac, 0x91, 0x6e, 0x97, 0x8e, 0x08, 0xe3, 0xfe, 0x9f, 0x9e, 0x9f, 0x4b, 0xcc, 0x5d, 0x1d, 0xb9, 0xbf, 0x07, 0x83, 0xfe, 0x51, 0x2a, 0xdf, 0x79, 0x2e, 0x07, 0xc9, 0x98, 0x9b, 0xbe, 0xb6, 0xe4, 0x0a, 0x20, 0x44, 0x86, 0xea, 0xb1, 0x61, 0x58, 0x11, 0x32, 0x8e, 0x7b, 0xb9, 0x67, 0x2d, 0xf0, 0x78, 0xb2, 0x93}, {0x1a, 0x65, 0xb3, 0x6f, 0xa2, 0x45, 0x29, 0x53, 0xd7, 0x23, 0x4d, 0xff, 0x8e, 0xe9, 0xb9, 0xef, 0x16, 0xa0, 0xdd, 0x48, 0xdf, 0x70, 0xd2, 0xe1, 0x56, 0xca, 0xd1, 0xd0, 0x4a, 0x9d, 0x63, 0x92, 0x2b, 0xfd, 0x7b, 0x87, 0x39, 0x3c, 0x12, 0xc7, 0xe5, 0x91, 0x31, 0x95, 0x78, 0xc4, 0x58, 0x95, 0x89, 0x6e, 0x2c, 0x90, 0xb4, 0x0b, 0xb2, 0xfe, 0x52, 0xc0, 0x86, 0xc4, 0x2e, 0x56, 0x97, 0x0c, 0x20, 0xf2, 0xbc, 0x6a, 0x9b, 0x89, 0xfb, 0xe9, 0x85, 0x95, 0xd6, 0x22, 0x5e, 0x4d, 0x6d, 0x83, 0x9d, 0xf4, 0xbe, 0x66, 0x05, 0x32, 0xb6, 0xe2, 0xf1, 0x96, 0x42, 0xa4, 0xc8, 0x8c, 0x1b, 0xec}, {0x43, 0x85, 0xff, 0xb9, 0xcf, 0x04, 0x83, 0x40, 0x70, 0x3a, 0x9c, 0x48, 0xb4, 0xc2, 0x99, 0x3b, 0xa0, 0x39, 0xf1, 0x39, 0x58, 0x7f, 0xd2, 0x49, 0x94, 0x3c, 0xc3, 0xe1, 0xb6, 0x56, 0x38, 0x55, 0x6f, 0xb5, 0x1a, 0x90, 0xa2, 0x04, 0x2f, 0x19, 0xf8, 0xb1, 0x65, 0x5a, 0xad, 0xcd, 0x1c, 0x56, 0x42, 0x38, 0xc2, 0x52, 0x09, 0xd6, 0x41, 0x98, 0x5d, 0x5f, 0xa5, 0xe7, 0xc2, 0x55, 0xa1, 0x09, 0x20, 0xf2, 0xbc, 0x6a, 0x9b, 0x89, 0xfb, 0xe9, 0x85, 0x95, 0xd6, 0x22, 0x5e, 0x4d, 0x6d, 0x83, 0x9d, 0xf4, 0xbe, 0x66, 0x05, 0x32, 0xb6, 0xe2, 0xf1, 0x96, 0x42, 0xa4, 0xc8, 0x8c, 0x1b, 0xec}}, - {{0xf2, 0x4a, 0x96, 0x57, 0xc3, 0x2f, 0xe6, 0x9f, 0xed, 0x7f, 0xcc, 0xe9, 0xea, 0xbe, 0xd2, 0x23, 0x4e, 0x47, 0x13, 0xd9, 0x53, 0x19, 0x31, 0x14, 0x0a, 0xd3, 0x9b, 0x95, 0xa7, 0x9c, 0x88, 0x5e, 0x08, 0xb2, 0x16, 0xda, 0x45, 0x61, 0x1d, 0x6b, 0xdf, 0xb1, 0x14, 0x0c, 0x66, 0xfd, 0x3a, 0xbe, 0x25, 0xdc, 0xfd, 0xcd, 0xcc, 0x5e, 0x28, 0x77, 0x5a, 0xa9, 0x8b, 0x84, 0x77, 0x26, 0x9d, 0xa6}, {0xea, 0xde, 0x4d, 0xab, 0x09, 0x02, 0xbf, 0x90, 0xf8, 0xae, 0x8b, 0x50, 0x01, 0xb2, 0x9d, 0x7c, 0x0a, 0x3b, 0x60, 0xda, 0x34, 0xa9, 0xbb, 0x4d, 0xa5, 0x53, 0x18, 0x65, 0xec, 0xaa, 0xc9, 0x29, 0xb2, 0xf7, 0x74, 0x14, 0x63, 0x5f, 0x88, 0xcf, 0x4e, 0x70, 0x1b, 0x11, 0x64, 0x73, 0x15, 0x6b, 0x5a, 0x8c, 0xb8, 0x4e, 0x0f, 0x83, 0xae, 0x4b, 0x5c, 0x52, 0x1c, 0x6a, 0x0f, 0x54, 0x77, 0xc8}, {0xae, 0xff, 0x55, 0xbf, 0x78, 0xb5, 0xde, 0x33, 0xeb, 0x87, 0xea, 0x13, 0x7d, 0x36, 0x22, 0x06, 0x32, 0xc4, 0x7e, 0xca, 0x65, 0x37, 0xcc, 0x83, 0x0e, 0xda, 0x54, 0xb3, 0xd2, 0xe6, 0xe7, 0x7f, 0xe1, 0x90, 0x11, 0x25, 0x16, 0x83, 0x25, 0x43, 0xb4, 0x38, 0x06, 0xbb, 0x6c, 0x62, 0x7d, 0x84, 0x1f, 0xf3, 0x7b, 0xeb, 0xae, 0x50, 0xd8, 0xfb, 0xb9, 0xf2, 0xf9, 0xc3, 0x6f, 0x59, 0xb7, 0xb0}, {0x95, 0x15, 0x83, 0x19, 0x56, 0x9c, 0x11, 0xd8, 0x31, 0x87, 0x1d, 0xe3, 0x3f, 0x07, 0x89, 0xb2, 0xcb, 0x81, 0xf0, 0xeb, 0x0b, 0x1e, 0x74, 0x08, 0xa2, 0x4a, 0x0e, 0x82, 0xc6, 0x45, 0x8c, 0x32, 0xb4, 0x8f, 0xfd, 0x76, 0xeb, 0x5e, 0xc7, 0x62, 0xdc, 0xcb, 0xee, 0xad, 0xcf, 0xcf, 0xea, 0x33, 0x9d, 0xb0, 0x02, 0x64, 0x66, 0x77, 0x14, 0x97, 0x0c, 0x6e, 0x79, 0xe8, 0x58, 0x32, 0x0f, 0xe6}, {0xcb, 0x2f, 0xaf, 0x53, 0xd8, 0x41, 0x48, 0x41, 0x6f, 0x36, 0x78, 0x80, 0x83, 0x5c, 0x0d, 0x4c, 0x1b, 0xf4, 0x39, 0xe0, 0x34, 0x4f, 0xc2, 0xb2, 0x4e, 0xf0, 0xac, 0xc2, 0xf8, 0x15, 0x7a, 0x81, 0x9f, 0x46, 0x2b, 0xe3, 0xb9, 0x39, 0x05, 0x89, 0xa2, 0xda, 0x1a, 0x63, 0x51, 0xb4, 0x78, 0x0f, 0xfe, 0x2f, 0x9d, 0xce, 0x99, 0x38, 0xa9, 0x7e, 0xcb, 0x80, 0x57, 0x9f, 0xa2, 0x28, 0x0f, 0x6a}, {0x1b, 0xec, 0x67, 0x50, 0xd1, 0x28, 0x65, 0x55, 0xb8, 0xde, 0x3b, 0x2e, 0x1e, 0x33, 0xd8, 0x1b, 0xba, 0x2e, 0x78, 0x6a, 0xb8, 0x0b, 0x8c, 0xa0, 0x55, 0x34, 0x25, 0x90, 0x9a, 0xe2, 0xf5, 0xaa, 0x95, 0x0c, 0x6f, 0x2a, 0xb0, 0x92, 0x1d, 0x48, 0x5b, 0x56, 0x8c, 0x82, 0x8f, 0xa7, 0x15, 0x75, 0x26, 0x61, 0x85, 0xc8, 0x7d, 0xda, 0xf5, 0x2a, 0xf3, 0x3c, 0x34, 0xc1, 0x20, 0x67, 0xbb, 0x04, 0xec, 0x7c, 0xe2, 0xcb, 0x31, 0xcf, 0x23, 0xda, 0x5d, 0x8a, 0x05, 0x00, 0x9b, 0x23, 0x34, 0xd0, 0xed, 0x56, 0x10, 0x0a, 0x90, 0x6b, 0x73, 0x26, 0x6b, 0xf0, 0xd7, 0xbc, 0xd8, 0xc7, 0x89, 0xc8}, {0x90, 0x43, 0x54, 0x87, 0x44, 0x00, 0x07, 0xca, 0xa8, 0x2b, 0xec, 0x55, 0xa0, 0xd2, 0x8c, 0x07, 0x03, 0xaa, 0x61, 0x1a, 0x7d, 0x0f, 0x90, 0x13, 0x67, 0x99, 0x46, 0x20, 0xcd, 0x70, 0xcb, 0xa7, 0x96, 0xdf, 0x0c, 0x13, 0xc4, 0x41, 0x11, 0xd6, 0xc3, 0x33, 0x02, 0x96, 0x4f, 0x1d, 0xbd, 0x06, 0xa9, 0xa1, 0x31, 0x0a, 0xc3, 0xdf, 0x6d, 0x52, 0x6c, 0xc6, 0xbe, 0xc5, 0xb6, 0x2a, 0xb1, 0x0f, 0xec, 0x7c, 0xe2, 0xcb, 0x31, 0xcf, 0x23, 0xda, 0x5d, 0x8a, 0x05, 0x00, 0x9b, 0x23, 0x34, 0xd0, 0xed, 0x56, 0x10, 0x0a, 0x90, 0x6b, 0x73, 0x26, 0x6b, 0xf0, 0xd7, 0xbc, 0xd8, 0xc7, 0x89, 0xc8}}, - {{0x4f, 0x3a, 0xdd, 0x0f, 0xcf, 0x7f, 0x27, 0xda, 0x27, 0xc4, 0xa6, 0x2b, 0x6b, 0xd1, 0x9f, 0x59, 0x73, 0x5f, 0xd4, 0xb7, 0xf0, 0x86, 0x16, 0xc9, 0xdd, 0xa6, 0xf9, 0x9b, 0x17, 0xb2, 0xb9, 0x71, 0xe7, 0x4c, 0xa1, 0x17, 0x79, 0xe0, 0xcc, 0xae, 0x10, 0xec, 0x28, 0x3a, 0x09, 0xf2, 0x8b, 0x34, 0x9c, 0xac, 0x16, 0x2a, 0xa9, 0x21, 0xe8, 0xa7, 0x18, 0xc0, 0xc4, 0x9f, 0x30, 0xa0, 0x25, 0x62}, {0x23, 0x4c, 0xd4, 0xae, 0x52, 0x30, 0xf6, 0x64, 0xb9, 0xe1, 0x47, 0xca, 0xf8, 0xf3, 0x3a, 0x6b, 0x8b, 0xf3, 0x29, 0xe2, 0x9b, 0x5d, 0xbb, 0x0a, 0x60, 0x52, 0x03, 0x40, 0x53, 0x5c, 0x9e, 0x35, 0x03, 0xd4, 0xec, 0xd7, 0x67, 0xf4, 0x92, 0xd2, 0x98, 0x96, 0xf2, 0xa7, 0xf4, 0x25, 0x6a, 0x80, 0x9c, 0x75, 0xc6, 0xf2, 0x1f, 0x67, 0x11, 0x00, 0x0d, 0xda, 0x1e, 0xb2, 0x58, 0xa7, 0x8c, 0x39}, {0x55, 0x1b, 0x80, 0xbb, 0xf3, 0xc5, 0x1a, 0x84, 0x34, 0xf5, 0x0a, 0x8a, 0x8a, 0xe1, 0x8c, 0xea, 0xa6, 0xfb, 0xd0, 0x26, 0xc9, 0xa2, 0x30, 0x37, 0x3e, 0xba, 0x98, 0xfe, 0x81, 0x8a, 0x52, 0x37, 0x0b, 0x74, 0x4e, 0x3d, 0x26, 0x8f, 0x82, 0x4b, 0xc0, 0x6a, 0x01, 0x10, 0x91, 0x8f, 0x89, 0xb5, 0x62, 0x3f, 0x1e, 0x70, 0xcc, 0x25, 0x77, 0x39, 0x74, 0x88, 0xdd, 0xbc, 0xbe, 0x72, 0x08, 0x63}, {0xe2, 0x9a, 0x46, 0xd2, 0x74, 0xdc, 0x0f, 0x8a, 0xa3, 0xbd, 0x20, 0xb7, 0xc7, 0xd9, 0x83, 0x4b, 0x58, 0xa6, 0xe3, 0xbd, 0xc5, 0x00, 0xb6, 0x18, 0x04, 0x25, 0x81, 0xbd, 0x99, 0xb3, 0xb1, 0x2a, 0x7a, 0x68, 0x6d, 0xe1, 0x3e, 0x23, 0x8d, 0x29, 0x9e, 0x7a, 0x30, 0x56, 0x4c, 0x22, 0xb6, 0xf4, 0x7d, 0x7d, 0x4f, 0xfd, 0x76, 0xa5, 0x9d, 0x05, 0x41, 0x7c, 0x7a, 0x2d, 0x7b, 0xbe, 0xcf, 0x73}, {0x7b, 0xae, 0x11, 0x86, 0x8a, 0x38, 0xbd, 0x56, 0x3c, 0xf3, 0x3c, 0x9c, 0x49, 0xa4, 0x68, 0x0f, 0x2b, 0xdf, 0xf2, 0xa1, 0xbc, 0xc2, 0xed, 0x08, 0x09, 0x96, 0xd0, 0x7e, 0x9b, 0xe3, 0x0a, 0x72, 0x13, 0x03, 0xd4, 0x35, 0x0a, 0x94, 0x60, 0x09, 0x4a, 0xaa, 0xca, 0x35, 0x8e, 0xed, 0x12, 0xdd, 0x26, 0x8f, 0xf8, 0xa9, 0xa2, 0x8a, 0x7f, 0xac, 0xf3, 0x09, 0xc7, 0x22, 0xc5, 0x73, 0xec, 0xa0}, {0xe9, 0xc5, 0x57, 0x0d, 0x85, 0xbf, 0x10, 0xe2, 0xd1, 0xf5, 0xd7, 0x22, 0xe9, 0x6a, 0x67, 0x8d, 0xd3, 0x9f, 0x1a, 0xef, 0x7f, 0xc0, 0x2b, 0xe1, 0xfd, 0x2c, 0xc2, 0x5f, 0x39, 0xf9, 0x34, 0xd0, 0x87, 0x94, 0x41, 0x8a, 0x65, 0xa5, 0x20, 0x48, 0xa4, 0x20, 0x5f, 0x7a, 0xc7, 0x37, 0x00, 0x60, 0x59, 0x84, 0x2a, 0x1d, 0xff, 0x02, 0xc3, 0xe8, 0x20, 0xaa, 0x39, 0x13, 0xac, 0xf3, 0xd7, 0x05, 0xbd, 0xef, 0x11, 0x66, 0x71, 0xb8, 0x9f, 0x1e, 0xe5, 0xee, 0x2e, 0x37, 0xfb, 0x34, 0xed, 0xc5, 0xa4, 0x40, 0x6e, 0x38, 0x31, 0x0a, 0x1c, 0xaf, 0x0d, 0xd3, 0x98, 0xac, 0x12, 0x40, 0xea, 0x9c}, {0xc6, 0xcd, 0x7a, 0xbd, 0x14, 0xdb, 0xe4, 0xed, 0xbf, 0x46, 0x70, 0x23, 0xbd, 0xdb, 0xc3, 0xce, 0x60, 0xd5, 0x6b, 0x17, 0x4c, 0x23, 0xfa, 0x78, 0x05, 0xcc, 0x18, 0xed, 0x42, 0x03, 0xa5, 0xb7, 0xdf, 0x28, 0x0e, 0xd4, 0x5d, 0x31, 0xd8, 0xb9, 0xdc, 0xe9, 0xf6, 0x26, 0xc5, 0xe1, 0xb3, 0x80, 0x0d, 0x62, 0xaf, 0x2d, 0xbd, 0xd6, 0xe4, 0xbb, 0x16, 0x82, 0xc8, 0x13, 0x2a, 0x6f, 0xb9, 0x06, 0xbd, 0xef, 0x11, 0x66, 0x71, 0xb8, 0x9f, 0x1e, 0xe5, 0xee, 0x2e, 0x37, 0xfb, 0x34, 0xed, 0xc5, 0xa4, 0x40, 0x6e, 0x38, 0x31, 0x0a, 0x1c, 0xaf, 0x0d, 0xd3, 0x98, 0xac, 0x12, 0x40, 0xea, 0x9c}}, - {{0x6f, 0x46, 0xcd, 0x96, 0xc4, 0x13, 0xf4, 0x11, 0x62, 0x49, 0x8c, 0x5c, 0x78, 0x27, 0xef, 0xc8, 0xb9, 0xe2, 0x7d, 0xf1, 0x0d, 0x37, 0xf2, 0xfe, 0x85, 0x35, 0x82, 0x60, 0x23, 0xb6, 0x7b, 0x17, 0xd2, 0x91, 0xef, 0x01, 0x9e, 0x99, 0x35, 0xab, 0xc7, 0xfb, 0xa1, 0xa3, 0x13, 0x44, 0x3f, 0x3c, 0x16, 0xcb, 0xd8, 0xf0, 0xbf, 0x9e, 0x65, 0x4d, 0x07, 0xe0, 0xfd, 0x8e, 0x32, 0x61, 0x95, 0xd5}, {0xb7, 0x81, 0x16, 0x2f, 0xcb, 0xa4, 0x30, 0x4e, 0x6d, 0xf5, 0xf0, 0x3f, 0xfe, 0xd9, 0x81, 0x20, 0xa6, 0x0e, 0x2b, 0xa8, 0xc5, 0xed, 0x0d, 0x9a, 0x28, 0x9c, 0xe3, 0xa9, 0xb7, 0xbf, 0x87, 0x0f, 0xa5, 0xf9, 0x33, 0xe7, 0xa6, 0x7f, 0x9b, 0xac, 0xb6, 0xcc, 0xaf, 0xfc, 0xa7, 0x4a, 0x4d, 0x36, 0x39, 0xa9, 0xb6, 0xf5, 0x09, 0xde, 0x8d, 0x37, 0x11, 0x07, 0xd1, 0x8a, 0xf5, 0x7b, 0x66, 0xe1}, {0xcc, 0xe0, 0x07, 0x62, 0xbe, 0x10, 0x8c, 0x3a, 0xa2, 0x96, 0x5d, 0x11, 0xc7, 0xd5, 0x50, 0xc3, 0xbb, 0x55, 0x21, 0xc5, 0x40, 0x27, 0x7d, 0xdb, 0xad, 0xd2, 0x61, 0x2a, 0x42, 0x5f, 0x94, 0x23, 0x77, 0x83, 0x3a, 0x99, 0xe8, 0xda, 0x79, 0x8c, 0x1e, 0xa8, 0x44, 0x04, 0xec, 0xf5, 0xd1, 0x55, 0x1e, 0x58, 0xf1, 0x6e, 0x4d, 0x27, 0xa4, 0x91, 0xec, 0x59, 0xc8, 0x17, 0x36, 0x58, 0x2a, 0x1f}, {0x6d, 0xf8, 0x73, 0xa3, 0x38, 0x61, 0x1d, 0x95, 0x09, 0xde, 0xe5, 0x26, 0x1b, 0x15, 0x16, 0xfb, 0xf5, 0x16, 0xa8, 0xf3, 0x9e, 0x3a, 0x6b, 0xb5, 0x8c, 0xee, 0xa8, 0x66, 0x79, 0xc3, 0x9e, 0xb4, 0xe1, 0xc2, 0x85, 0x0e, 0x86, 0x10, 0x5a, 0x4e, 0x8b, 0x4c, 0x0a, 0x7a, 0xd8, 0x8a, 0x48, 0xf4, 0xa0, 0x79, 0x37, 0xe3, 0xa5, 0x90, 0x05, 0x5e, 0xbd, 0xa1, 0xf6, 0x09, 0x58, 0x9c, 0x6f, 0x09}, {0x66, 0x47, 0x6d, 0x60, 0x06, 0x2d, 0x90, 0x8f, 0xae, 0x6c, 0x01, 0xe9, 0xb0, 0xf9, 0x6b, 0xa5, 0x4a, 0xe1, 0xdb, 0xd3, 0x64, 0x42, 0x37, 0x5c, 0x11, 0x40, 0x7a, 0xce, 0x4e, 0x83, 0xc3, 0x2c, 0x2e, 0xd2, 0x67, 0x76, 0xfb, 0x8c, 0x5d, 0xab, 0xe8, 0xb8, 0xd6, 0x2b, 0xf8, 0x86, 0xff, 0x96, 0xf3, 0xa8, 0x0e, 0x2b, 0x1a, 0x68, 0xf5, 0xe4, 0xee, 0x49, 0xa6, 0x8c, 0x41, 0x1f, 0x97, 0xbf}, {0x81, 0x92, 0x4e, 0xc6, 0xab, 0x00, 0xdd, 0xf9, 0xf9, 0xb7, 0xe0, 0x0a, 0xa9, 0x3f, 0x0a, 0xf9, 0x32, 0x73, 0xf6, 0x22, 0xec, 0x95, 0xd9, 0x20, 0x8a, 0x3f, 0xeb, 0x0d, 0xc7, 0x79, 0x6f, 0xb3, 0x85, 0xf4, 0xe1, 0x11, 0xe1, 0xcc, 0xaa, 0x1b, 0xfd, 0xf3, 0x43, 0xff, 0x66, 0x73, 0x0f, 0x09, 0xcc, 0xa4, 0x6c, 0xb8, 0x2a, 0x0f, 0x53, 0x58, 0x63, 0x32, 0x06, 0xd9, 0x6b, 0x1a, 0x14, 0x04, 0x85, 0x3f, 0x2f, 0x2b, 0x05, 0xfb, 0xed, 0xe9, 0x08, 0x0d, 0x21, 0x49, 0xc9, 0x79, 0xdf, 0x6f, 0x77, 0x89, 0xd7, 0x74, 0x09, 0x57, 0x1a, 0xd2, 0xa7, 0x43, 0xbf, 0x08, 0x8e, 0x98, 0xbc, 0x2f}, {0xe3, 0xb1, 0xc4, 0x81, 0xe6, 0xec, 0x07, 0x58, 0xa4, 0xcb, 0x7e, 0xd5, 0xae, 0x9d, 0x43, 0xf1, 0xb7, 0xe2, 0x0a, 0x1f, 0xd5, 0xe8, 0x14, 0xba, 0x22, 0xff, 0xb7, 0x20, 0x76, 0x08, 0xdc, 0x9a, 0x44, 0x4c, 0x1c, 0xcd, 0x38, 0x4d, 0xb5, 0xd8, 0xa9, 0x1b, 0x9d, 0xbb, 0x13, 0x5a, 0x6c, 0xe9, 0x5d, 0xa4, 0x42, 0x0e, 0xde, 0x9a, 0x47, 0x8a, 0x2a, 0x97, 0x42, 0x86, 0x87, 0x98, 0x3f, 0x04, 0x85, 0x3f, 0x2f, 0x2b, 0x05, 0xfb, 0xed, 0xe9, 0x08, 0x0d, 0x21, 0x49, 0xc9, 0x79, 0xdf, 0x6f, 0x77, 0x89, 0xd7, 0x74, 0x09, 0x57, 0x1a, 0xd2, 0xa7, 0x43, 0xbf, 0x08, 0x8e, 0x98, 0xbc, 0x2f}}, - {{0xff, 0xe3, 0x69, 0x7b, 0x62, 0x45, 0x40, 0x5f, 0x1c, 0x49, 0x65, 0xd6, 0xae, 0x24, 0x16, 0x84, 0xfa, 0x69, 0x6c, 0x1f, 0x6c, 0x65, 0xee, 0x52, 0xe9, 0x6c, 0x54, 0xc7, 0x31, 0x9b, 0xc2, 0x74, 0x4f, 0xc0, 0x16, 0xb8, 0xf8, 0x75, 0x5f, 0x45, 0xb5, 0xf3, 0xa0, 0xd9, 0xbe, 0x25, 0x82, 0xbd, 0x3c, 0x03, 0xe0, 0x14, 0x15, 0x6a, 0xd5, 0x64, 0x08, 0x65, 0x13, 0x33, 0xc2, 0xab, 0xe0, 0x45}, {0x6f, 0x5a, 0x90, 0x80, 0x25, 0x13, 0xc2, 0xa7, 0xfe, 0x1c, 0xa1, 0x07, 0x81, 0x4b, 0x09, 0xd3, 0xbd, 0xda, 0x55, 0xa8, 0xaa, 0x62, 0x19, 0x03, 0xe9, 0x9f, 0x77, 0xef, 0xff, 0xd4, 0x5e, 0x53, 0xbc, 0x9d, 0x71, 0xb8, 0xc4, 0xc2, 0x85, 0xb9, 0xb4, 0x3d, 0x95, 0xb8, 0xfd, 0x44, 0xb7, 0xc8, 0x6f, 0x93, 0x15, 0x04, 0x16, 0x7e, 0x01, 0xf2, 0x09, 0x23, 0x96, 0x69, 0xe5, 0x65, 0x52, 0x34}, {0xaf, 0xfe, 0x4f, 0x34, 0x4e, 0xfe, 0x51, 0xa5, 0xb2, 0xd8, 0x31, 0x74, 0x7b, 0xae, 0xfb, 0xb9, 0x33, 0xc1, 0xdc, 0x66, 0xe6, 0x95, 0x9e, 0xce, 0x77, 0x7d, 0x55, 0x3c, 0xa6, 0x6c, 0x09, 0x23, 0x5a, 0x1a, 0x5e, 0x1a, 0x41, 0xd3, 0xad, 0x5f, 0x86, 0xd0, 0x14, 0xf5, 0xe0, 0xda, 0xf1, 0xce, 0x19, 0x90, 0x45, 0x0c, 0x4c, 0xb1, 0xd3, 0xc8, 0x4c, 0xdb, 0x7e, 0x49, 0xf5, 0xac, 0xde, 0xff}, {0x1b, 0x9b, 0x6b, 0x30, 0xd3, 0x19, 0x37, 0x83, 0xad, 0x05, 0xca, 0xba, 0x22, 0x85, 0x33, 0x7f, 0x55, 0x60, 0xe3, 0x14, 0x8c, 0x39, 0x87, 0xd1, 0x4c, 0x21, 0x27, 0xa0, 0xae, 0x4a, 0x56, 0x15, 0x50, 0x6c, 0x99, 0xca, 0xff, 0xde, 0x10, 0xc6, 0x9f, 0x6c, 0x70, 0xd1, 0x66, 0xb4, 0x87, 0xd8, 0xfc, 0x46, 0xf2, 0xcf, 0x0c, 0xd8, 0xc3, 0x14, 0x5d, 0x27, 0xbd, 0xed, 0x32, 0x36, 0x7c, 0xed}, {0x64, 0x6b, 0x74, 0xc7, 0x60, 0x36, 0xc5, 0xe4, 0xb6, 0xde, 0x02, 0x1a, 0x09, 0xaf, 0x65, 0xb1, 0x94, 0xa3, 0xf4, 0x95, 0xf5, 0xb0, 0xef, 0x86, 0xb5, 0x13, 0x26, 0x0b, 0xe8, 0xc5, 0x5c, 0x77, 0xf5, 0xe6, 0xb6, 0x10, 0x36, 0x87, 0xa3, 0xd2, 0x7c, 0x17, 0x2c, 0xb9, 0xb0, 0x90, 0x9e, 0x8c, 0x0a, 0x7d, 0x73, 0xb2, 0x29, 0xeb, 0xa7, 0x85, 0xd7, 0x04, 0x14, 0xf9, 0x77, 0xb7, 0xf4, 0x89}, {0x7f, 0x1c, 0x5a, 0x57, 0x14, 0xf6, 0x30, 0x07, 0xf9, 0xfe, 0x42, 0x98, 0xcb, 0x3d, 0xac, 0x04, 0x30, 0x0d, 0xc6, 0xd0, 0x4f, 0x8a, 0xbc, 0xdd, 0x3e, 0xc3, 0xb7, 0x74, 0xc8, 0x3b, 0x1a, 0xcc, 0x6a, 0x54, 0x9e, 0xb9, 0xbe, 0xf0, 0x7c, 0x35, 0x35, 0x1a, 0x50, 0x4c, 0xc2, 0x38, 0x41, 0x46, 0xc8, 0xc4, 0x81, 0x2b, 0x26, 0x56, 0x6f, 0x8a, 0x9f, 0x74, 0x87, 0xe0, 0x01, 0x82, 0xe2, 0x09, 0xf3, 0x9a, 0xc5, 0x33, 0x5a, 0x7d, 0xb6, 0xbb, 0xff, 0x20, 0x4d, 0xc1, 0x99, 0x3d, 0xcc, 0x5a, 0xc7, 0xd1, 0xbe, 0x4c, 0xcf, 0xc8, 0x09, 0x79, 0x15, 0x5e, 0x0c, 0xc6, 0x26, 0x36, 0xe6, 0xd9}, {0x4d, 0x2f, 0x08, 0x84, 0x32, 0xcf, 0xe0, 0x3b, 0xa8, 0x3e, 0xa5, 0xf8, 0x3a, 0xe8, 0xa9, 0x04, 0x5a, 0x74, 0x67, 0xcb, 0x41, 0x22, 0xc5, 0xc4, 0x9a, 0xa5, 0xc1, 0xa7, 0x94, 0x8b, 0xa5, 0x35, 0x00, 0x00, 0x1a, 0xaf, 0xfb, 0xed, 0x40, 0xb8, 0x2b, 0x28, 0xf1, 0xb1, 0x02, 0xd3, 0x8b, 0xc0, 0x32, 0x4a, 0xa5, 0x0a, 0xa4, 0xc3, 0xbf, 0xb3, 0xf5, 0xb7, 0x65, 0x8e, 0x88, 0xdf, 0xd0, 0x0e, 0xf3, 0x9a, 0xc5, 0x33, 0x5a, 0x7d, 0xb6, 0xbb, 0xff, 0x20, 0x4d, 0xc1, 0x99, 0x3d, 0xcc, 0x5a, 0xc7, 0xd1, 0xbe, 0x4c, 0xcf, 0xc8, 0x09, 0x79, 0x15, 0x5e, 0x0c, 0xc6, 0x26, 0x36, 0xe6, 0xd9}}, - {{0xc8, 0x8e, 0x1c, 0xea, 0x02, 0x6a, 0xfd, 0x88, 0x8b, 0xa9, 0x9d, 0xdd, 0xba, 0xea, 0x77, 0x30, 0x88, 0x1a, 0x93, 0x49, 0xda, 0x05, 0x18, 0xbb, 0x4a, 0x6a, 0x11, 0xc4, 0x48, 0x72, 0x77, 0x1f, 0x6e, 0x2b, 0x9a, 0xe3, 0x27, 0xbe, 0xe1, 0x75, 0x32, 0x30, 0xa6, 0x12, 0x26, 0x44, 0xbf, 0xb2, 0xa5, 0x51, 0x0b, 0x48, 0x3a, 0xea, 0xc5, 0xd4, 0x24, 0x3f, 0x4e, 0xe8, 0xe5, 0xc3, 0xfb, 0xc2}, {0xcb, 0x56, 0x3c, 0x00, 0x28, 0x15, 0x72, 0x16, 0x23, 0x4e, 0x2e, 0x2c, 0x8c, 0xe8, 0x7c, 0x44, 0x82, 0x2a, 0xe0, 0x57, 0xa3, 0x0a, 0xc4, 0x42, 0xb5, 0x07, 0xe1, 0x1b, 0x78, 0x8b, 0x3d, 0x4d, 0xcb, 0xe4, 0x56, 0x72, 0x0b, 0x85, 0x52, 0xd8, 0x55, 0xe2, 0xcd, 0x38, 0xd2, 0x83, 0xb6, 0x05, 0xd2, 0x9f, 0x63, 0x9e, 0x7f, 0xca, 0xe5, 0x95, 0x36, 0x61, 0x9b, 0xca, 0x09, 0x27, 0x53, 0x82}, {0x24, 0x67, 0x10, 0xd6, 0x8a, 0x1a, 0x8e, 0xb8, 0x53, 0xef, 0xb7, 0x67, 0x2a, 0xfd, 0xb8, 0xd6, 0xe3, 0xf7, 0x41, 0x95, 0x8c, 0x50, 0xca, 0x1d, 0x21, 0x21, 0x41, 0xd1, 0xef, 0x2d, 0x9b, 0x53, 0xa9, 0x42, 0xcd, 0xda, 0x6d, 0x12, 0x1b, 0xbd, 0x0a, 0xe1, 0x4d, 0x95, 0xc6, 0xaa, 0x40, 0xfd, 0x98, 0xfb, 0x26, 0x21, 0x5e, 0xaf, 0x8e, 0x6b, 0xc9, 0x36, 0x2c, 0x66, 0x31, 0x24, 0x45, 0x87}, {0x5e, 0xf9, 0x1d, 0x10, 0xb5, 0x79, 0x1f, 0x80, 0x85, 0x90, 0xc3, 0x7f, 0x2b, 0x73, 0xbf, 0x83, 0x0b, 0x5d, 0x46, 0xae, 0x79, 0xef, 0x09, 0x71, 0x29, 0xfb, 0x83, 0xde, 0x1f, 0xe2, 0xdb, 0x1b, 0xa2, 0x22, 0xee, 0x50, 0x21, 0x9d, 0x9c, 0x35, 0x14, 0x48, 0x13, 0xa5, 0xd1, 0x68, 0xf4, 0x61, 0x1f, 0xd7, 0xe2, 0xd6, 0x42, 0x1c, 0xdc, 0x58, 0xec, 0x8b, 0x03, 0x6b, 0xdf, 0x64, 0x06, 0x30}, {0xf9, 0xa6, 0x88, 0x74, 0x07, 0x19, 0x15, 0x38, 0xaf, 0xac, 0x07, 0x10, 0xe0, 0xd9, 0x22, 0xf3, 0x78, 0xb0, 0xbf, 0x60, 0xa3, 0x0f, 0xea, 0x0f, 0xa8, 0x64, 0xa9, 0xa3, 0x82, 0xe1, 0x4c, 0x29, 0x36, 0x22, 0x6d, 0x43, 0x9c, 0xde, 0x22, 0xbf, 0xc6, 0x85, 0xf7, 0xe9, 0xe0, 0x79, 0x80, 0xfe, 0x9d, 0xd6, 0x24, 0xbd, 0x29, 0xa4, 0x8c, 0x35, 0x21, 0x87, 0x45, 0x7f, 0x88, 0xd9, 0x9a, 0x9d}, {0x49, 0x43, 0x19, 0x14, 0xcc, 0x4a, 0x11, 0x01, 0x05, 0xd1, 0x4e, 0x39, 0x6d, 0xb0, 0x22, 0x65, 0x32, 0x6e, 0x67, 0x04, 0x50, 0x85, 0x53, 0x42, 0x90, 0x2c, 0xc0, 0x63, 0x2f, 0xbd, 0x15, 0x90, 0x1b, 0x3f, 0x03, 0x90, 0x16, 0x7f, 0x7b, 0x49, 0x74, 0xd0, 0x3d, 0x81, 0x80, 0x1e, 0x9e, 0x2e, 0xa9, 0x13, 0x6a, 0x10, 0x14, 0xc1, 0xfd, 0xf9, 0x25, 0x3a, 0x1d, 0x52, 0x93, 0x0a, 0x77, 0x03, 0xa2, 0xdd, 0xce, 0x9f, 0x2a, 0x35, 0xc9, 0x93, 0x7c, 0xa2, 0x2c, 0xf6, 0x38, 0x73, 0xb3, 0xab, 0x7f, 0x55, 0xb6, 0x62, 0xa2, 0x8d, 0x6a, 0x3e, 0x88, 0x04, 0x9b, 0xa2, 0x19, 0x64, 0x55, 0x01}, {0x22, 0x03, 0x49, 0x58, 0x76, 0x3c, 0x85, 0x45, 0x5e, 0x73, 0x78, 0x8f, 0x65, 0xc9, 0x50, 0xf8, 0xd7, 0x16, 0x92, 0xa4, 0xd1, 0x79, 0xce, 0xf3, 0x00, 0x34, 0x38, 0xb8, 0xcc, 0x96, 0x9f, 0xa6, 0x87, 0x28, 0xcb, 0x19, 0x28, 0xad, 0x83, 0xb5, 0x09, 0x96, 0x54, 0xe8, 0x2a, 0xb9, 0x9b, 0xff, 0x60, 0x85, 0x31, 0x28, 0x62, 0x36, 0xd2, 0x0e, 0xad, 0x2a, 0xe1, 0x84, 0x80, 0xeb, 0x6f, 0x00, 0xa2, 0xdd, 0xce, 0x9f, 0x2a, 0x35, 0xc9, 0x93, 0x7c, 0xa2, 0x2c, 0xf6, 0x38, 0x73, 0xb3, 0xab, 0x7f, 0x55, 0xb6, 0x62, 0xa2, 0x8d, 0x6a, 0x3e, 0x88, 0x04, 0x9b, 0xa2, 0x19, 0x64, 0x55, 0x01}}, - {{0xeb, 0x18, 0x95, 0x94, 0x5f, 0x15, 0x8c, 0xb8, 0x4d, 0x6e, 0x7d, 0xc0, 0x96, 0x6c, 0x52, 0xa2, 0x5f, 0x43, 0x67, 0xc2, 0x3a, 0x10, 0x5b, 0xf1, 0x8f, 0x21, 0x89, 0x06, 0x77, 0xe9, 0xab, 0x2e, 0xcd, 0x17, 0x9c, 0x9a, 0xd7, 0x89, 0x7e, 0x53, 0x58, 0x60, 0x9b, 0xce, 0x90, 0xd9, 0x13, 0x2d, 0x78, 0xc4, 0x2c, 0x1c, 0x4c, 0xe8, 0x23, 0x70, 0xff, 0xa0, 0x42, 0x98, 0x25, 0x40, 0xd6, 0xd8}, {0xb6, 0xfb, 0xdd, 0x5d, 0x35, 0xf2, 0x2b, 0x89, 0xda, 0x8e, 0x90, 0xee, 0x03, 0x4e, 0x75, 0xdb, 0x4c, 0x45, 0xc8, 0x00, 0xde, 0x06, 0x27, 0xde, 0x44, 0xb5, 0x5b, 0xc7, 0x56, 0xc3, 0xf5, 0xbb, 0xee, 0xa6, 0x21, 0xd4, 0xd9, 0xb9, 0x24, 0x9c, 0x4c, 0xbc, 0x23, 0xe5, 0xeb, 0x05, 0xb6, 0xd0, 0xd0, 0xbf, 0x49, 0x95, 0x01, 0xb4, 0x97, 0xad, 0xb5, 0x71, 0x8d, 0x4b, 0x32, 0xd0, 0xdd, 0x1a}, {0xfd, 0x11, 0xd7, 0xe4, 0x46, 0xcd, 0xd8, 0x44, 0x89, 0x0a, 0xe7, 0x44, 0x59, 0xe9, 0xcf, 0x9f, 0xd6, 0xf1, 0x74, 0x56, 0x04, 0x78, 0xfa, 0x29, 0x46, 0x8a, 0x8d, 0x1b, 0xbe, 0x41, 0x92, 0x1c, 0x8d, 0x74, 0x01, 0x1b, 0xc1, 0xf8, 0x26, 0xf4, 0xc2, 0x68, 0xc3, 0x23, 0x8c, 0x68, 0x7c, 0x0a, 0xad, 0xdd, 0x50, 0x10, 0xcf, 0xdb, 0x78, 0xc5, 0x79, 0x28, 0x37, 0x63, 0x92, 0x1a, 0x1d, 0xea}, {0xd2, 0x2a, 0xf0, 0x66, 0x15, 0x8b, 0xcb, 0x83, 0xcf, 0x34, 0xa1, 0x33, 0x6b, 0xd5, 0xa8, 0x98, 0x3b, 0xd7, 0x09, 0x0d, 0x70, 0xa5, 0x8a, 0xc0, 0x73, 0xcf, 0xde, 0x59, 0xd5, 0x13, 0x41, 0xd2, 0x43, 0x8b, 0xb4, 0xc3, 0x5b, 0x6f, 0xf1, 0xed, 0x47, 0x76, 0xe6, 0x5e, 0xb8, 0x2a, 0x7e, 0x20, 0x91, 0xa0, 0x9d, 0xc1, 0xa2, 0x0a, 0x6d, 0x97, 0x7d, 0xeb, 0xe3, 0x64, 0x5f, 0x86, 0xff, 0x3e}, {0x45, 0xd8, 0xdc, 0xe4, 0x3a, 0x3a, 0x44, 0xdc, 0x7f, 0xa8, 0x92, 0x11, 0x1b, 0x4f, 0xfa, 0xcf, 0x21, 0xff, 0xfb, 0x20, 0xb0, 0x02, 0x6d, 0x0e, 0x1c, 0xde, 0xe8, 0x51, 0xd8, 0x2c, 0x72, 0x0e, 0xbf, 0xf6, 0x9a, 0xd3, 0xd3, 0xfe, 0xfa, 0x98, 0x4e, 0xc2, 0xf0, 0x16, 0xda, 0x39, 0x93, 0xc4, 0xe0, 0x33, 0x9a, 0x43, 0xe8, 0x7a, 0xc5, 0x0f, 0x0b, 0xa4, 0x45, 0xf0, 0x5e, 0x7a, 0xa9, 0x42}, {0xdb, 0x4e, 0x17, 0x76, 0x8b, 0x3c, 0x98, 0x7f, 0x58, 0x76, 0x97, 0xc9, 0x3f, 0x99, 0x01, 0x05, 0x42, 0x7e, 0xfd, 0x83, 0x99, 0xaa, 0x19, 0xb5, 0x72, 0x4c, 0x69, 0xed, 0x6e, 0x21, 0x79, 0x6e, 0x3b, 0x71, 0xe5, 0xab, 0x23, 0x84, 0xe7, 0xfe, 0x58, 0x2b, 0x0d, 0x1e, 0x75, 0x7c, 0x29, 0xb3, 0x2d, 0x66, 0xc2, 0x45, 0x88, 0xac, 0x86, 0x29, 0xe4, 0xaa, 0x9e, 0x71, 0xa1, 0x88, 0xf9, 0x06, 0xda, 0xa3, 0xdd, 0x7b, 0x6c, 0xd9, 0xc9, 0x73, 0xe9, 0x56, 0xd1, 0xee, 0x5b, 0xf9, 0xae, 0xc0, 0x29, 0xbe, 0x20, 0x6c, 0xc7, 0xf9, 0xc5, 0x2d, 0x6d, 0xad, 0x8f, 0x49, 0xf8, 0x17, 0xdb, 0x7a}, {0xb8, 0xb7, 0xec, 0xeb, 0x3e, 0x40, 0x77, 0x6c, 0xab, 0x10, 0xfe, 0x9f, 0xd1, 0x40, 0xfe, 0xd2, 0x88, 0x8e, 0xb0, 0x55, 0xae, 0x75, 0xb1, 0xcc, 0x9d, 0x6c, 0x11, 0x28, 0x95, 0x38, 0x9f, 0xb9, 0x59, 0xe2, 0x29, 0xc3, 0xbc, 0x09, 0x16, 0x1f, 0x17, 0x9e, 0x15, 0x78, 0x09, 0x61, 0x07, 0x9e, 0xad, 0x67, 0x98, 0xa9, 0x24, 0xff, 0xf9, 0x4b, 0xa2, 0x76, 0x09, 0xa0, 0xd7, 0x1b, 0xed, 0x05, 0xda, 0xa3, 0xdd, 0x7b, 0x6c, 0xd9, 0xc9, 0x73, 0xe9, 0x56, 0xd1, 0xee, 0x5b, 0xf9, 0xae, 0xc0, 0x29, 0xbe, 0x20, 0x6c, 0xc7, 0xf9, 0xc5, 0x2d, 0x6d, 0xad, 0x8f, 0x49, 0xf8, 0x17, 0xdb, 0x7a}}, - {{0xc3, 0x92, 0x4d, 0x01, 0x9c, 0xea, 0x5a, 0x8d, 0xbd, 0x5c, 0x12, 0x58, 0x6d, 0x03, 0x26, 0xbf, 0xa4, 0xdd, 0xf7, 0x26, 0xa4, 0x0d, 0x22, 0xe0, 0xbd, 0xcc, 0x6f, 0x30, 0x9e, 0xf9, 0x4c, 0x1f, 0x03, 0x52, 0xab, 0x38, 0xe9, 0x9c, 0x08, 0x9c, 0x09, 0xe5, 0x87, 0x5c, 0x24, 0x1a, 0xe2, 0x75, 0xcb, 0x18, 0x8a, 0x63, 0x50, 0xd1, 0x23, 0x45, 0x49, 0x93, 0x40, 0x2c, 0x09, 0xd4, 0xac, 0x39}, {0xd4, 0xe7, 0xb7, 0x05, 0xfd, 0xd6, 0xf3, 0x57, 0xfb, 0xc2, 0x2f, 0x2c, 0x71, 0x80, 0xf5, 0xc3, 0xa6, 0x0a, 0x23, 0x9d, 0x1d, 0xa8, 0x68, 0x10, 0x8a, 0xfa, 0x68, 0x9d, 0x2b, 0xcf, 0x96, 0xa9, 0xe6, 0x0e, 0x07, 0x32, 0x23, 0x09, 0x87, 0x16, 0xc5, 0xbb, 0x76, 0x22, 0xfc, 0xb4, 0x59, 0x6d, 0x67, 0xfd, 0x29, 0x51, 0x95, 0x4c, 0xe2, 0x8c, 0x18, 0xab, 0xda, 0x84, 0xc3, 0x62, 0x80, 0x14}, {0xc9, 0xa1, 0xfe, 0xc3, 0x48, 0x0d, 0xee, 0x54, 0x44, 0xff, 0x9c, 0x46, 0x04, 0x0e, 0x74, 0xda, 0xa4, 0x6a, 0x56, 0x02, 0x5f, 0x76, 0x0e, 0xb5, 0xc1, 0xc9, 0xe9, 0xb2, 0x6e, 0x07, 0x49, 0x0c, 0xf7, 0x4b, 0xee, 0xd6, 0x0a, 0xad, 0x94, 0x03, 0x58, 0x2d, 0x60, 0x95, 0xf8, 0x16, 0x7b, 0x49, 0x0b, 0x01, 0x66, 0x3e, 0x17, 0x01, 0xe5, 0x54, 0x7d, 0xd7, 0xbb, 0x10, 0xd1, 0xad, 0xad, 0x79}, {0xb2, 0xd8, 0x10, 0x29, 0xeb, 0xb8, 0x4e, 0x2b, 0x39, 0x85, 0x5c, 0xb3, 0xdc, 0xf5, 0x87, 0xca, 0xca, 0x9c, 0x7a, 0x8c, 0x2b, 0x08, 0xe8, 0x25, 0xe2, 0xcf, 0x70, 0xe2, 0xe6, 0xfb, 0xdb, 0x0c, 0xc3, 0x0d, 0x71, 0x11, 0x83, 0x65, 0xf2, 0x71, 0x08, 0x1b, 0x32, 0x6e, 0x6c, 0x51, 0x50, 0xf1, 0xf6, 0x4b, 0x54, 0x63, 0x16, 0x7f, 0xfd, 0x80, 0x05, 0x61, 0x63, 0xf1, 0x80, 0x6a, 0x0b, 0xfd}, {0xa7, 0x4b, 0x75, 0x38, 0x90, 0x64, 0x96, 0x7b, 0xda, 0x5e, 0x08, 0x9b, 0x80, 0xc4, 0x72, 0x3f, 0x73, 0xb2, 0xdb, 0xd3, 0x4a, 0xed, 0xa4, 0xdc, 0x5c, 0x79, 0xe5, 0x0f, 0x7a, 0xd3, 0x0c, 0xac, 0xf9, 0x99, 0x5c, 0x1a, 0x0f, 0xb3, 0x1a, 0x0f, 0x5c, 0xc3, 0x9e, 0x1a, 0x2b, 0xfa, 0xc3, 0xf0, 0x40, 0xe5, 0x5f, 0x36, 0xd2, 0x98, 0x31, 0xa1, 0xaf, 0x18, 0x5f, 0xae, 0x92, 0xf3, 0x9e, 0xc0}, {0xf9, 0xbf, 0x52, 0xe6, 0xd3, 0xe1, 0x5d, 0xd3, 0x30, 0xf3, 0xa1, 0x0c, 0xc8, 0x5a, 0x97, 0x55, 0xab, 0x67, 0x67, 0xd0, 0x00, 0x62, 0x7b, 0x80, 0x70, 0xbf, 0x24, 0xd0, 0x09, 0x8b, 0x07, 0x77, 0xeb, 0x3e, 0xf0, 0x5d, 0xdf, 0x7b, 0xa9, 0x7d, 0xa4, 0x6a, 0x0d, 0xf1, 0xac, 0x83, 0x7d, 0x64, 0xb5, 0xf4, 0xc6, 0xc4, 0x12, 0x0c, 0x55, 0x9f, 0x67, 0xbb, 0xd5, 0xe3, 0xd3, 0xdb, 0x17, 0x0f, 0x90, 0x2f, 0x8f, 0xc9, 0xfd, 0x4e, 0x6c, 0x8b, 0xe6, 0x99, 0xfa, 0xda, 0x8f, 0x1f, 0xe6, 0xc3, 0xeb, 0xd8, 0x14, 0x20, 0xcc, 0x3c, 0x1c, 0x23, 0x77, 0x28, 0x9b, 0x22, 0x9a, 0x5a, 0x0c, 0x43}, {0xa2, 0x78, 0x37, 0xc9, 0x63, 0xe1, 0x31, 0x36, 0xc2, 0x58, 0xac, 0xca, 0xbb, 0xa2, 0x84, 0xaa, 0xb3, 0x82, 0xe2, 0x19, 0xb7, 0x14, 0x96, 0x27, 0x77, 0xfa, 0xa1, 0x02, 0xaa, 0xff, 0x55, 0x82, 0xba, 0xc0, 0x38, 0x1a, 0x69, 0x35, 0x48, 0x87, 0xc2, 0xeb, 0x48, 0x08, 0xea, 0xc5, 0x6b, 0xfc, 0x84, 0x60, 0x4e, 0xce, 0xd7, 0xd2, 0x86, 0x8b, 0x76, 0xf3, 0x46, 0xe1, 0x87, 0x1f, 0xff, 0x09, 0x90, 0x2f, 0x8f, 0xc9, 0xfd, 0x4e, 0x6c, 0x8b, 0xe6, 0x99, 0xfa, 0xda, 0x8f, 0x1f, 0xe6, 0xc3, 0xeb, 0xd8, 0x14, 0x20, 0xcc, 0x3c, 0x1c, 0x23, 0x77, 0x28, 0x9b, 0x22, 0x9a, 0x5a, 0x0c, 0x43}}, - {{0x0e, 0xa6, 0x0c, 0xef, 0x12, 0xd6, 0x7d, 0x71, 0xd4, 0x88, 0x73, 0x86, 0x9a, 0x88, 0x8f, 0x5b, 0xd1, 0xb6, 0x12, 0xc4, 0x93, 0x8b, 0x5f, 0xee, 0xdd, 0x9c, 0x2a, 0x7f, 0x4d, 0xfd, 0xba, 0x00, 0x09, 0x45, 0x77, 0xd2, 0xcf, 0xcd, 0x3a, 0x6f, 0x27, 0x44, 0xe2, 0x55, 0x3e, 0x79, 0x88, 0x4d, 0x5f, 0x38, 0x34, 0xe8, 0xe7, 0xc6, 0x3a, 0xde, 0xef, 0x99, 0x15, 0xea, 0x88, 0x79, 0xd7, 0xca}, {0xa0, 0x9a, 0x0a, 0x3a, 0x42, 0x35, 0x54, 0x78, 0xb9, 0x82, 0x52, 0xb4, 0xc8, 0x5c, 0x4a, 0x03, 0xa1, 0xb9, 0x27, 0xcc, 0x99, 0xec, 0x03, 0xdf, 0xdd, 0x6e, 0xde, 0xef, 0x8f, 0x7f, 0xdc, 0x5a, 0xc3, 0xcb, 0x0e, 0xa2, 0x7e, 0x93, 0xe6, 0xdd, 0xbd, 0xf1, 0x1b, 0x03, 0x29, 0x63, 0x72, 0x11, 0x72, 0x3d, 0x24, 0x6f, 0xdf, 0x8e, 0xed, 0xa4, 0xe2, 0x2a, 0x4c, 0x00, 0xe2, 0xc4, 0x55, 0x1b}, {0xb2, 0xf1, 0xff, 0xf6, 0x3a, 0x26, 0xe1, 0x74, 0x52, 0xba, 0xee, 0x28, 0xb6, 0x56, 0x90, 0x59, 0xde, 0x92, 0x5f, 0x84, 0xd1, 0x87, 0xe2, 0x64, 0xce, 0xdc, 0x94, 0x3c, 0xb4, 0xf8, 0x01, 0x0a, 0x86, 0x2f, 0xfe, 0x79, 0x03, 0x72, 0xfc, 0x26, 0x21, 0xc3, 0x1e, 0xec, 0x63, 0x29, 0x64, 0xcb, 0x5f, 0xcc, 0xb6, 0x78, 0xf7, 0xc8, 0xd1, 0xf8, 0x5c, 0xc4, 0x4b, 0xc0, 0xc3, 0x75, 0x3e, 0x46}, {0x03, 0x4b, 0xb9, 0xd1, 0x50, 0xa3, 0x79, 0xbe, 0x74, 0xa3, 0xb5, 0xd8, 0x28, 0x1b, 0x6d, 0x72, 0x68, 0x0a, 0x9b, 0x19, 0xc9, 0x13, 0xc4, 0x04, 0x94, 0x0a, 0xcb, 0x72, 0xff, 0x7d, 0xb6, 0x9a, 0x1c, 0xfd, 0xe4, 0xa3, 0x75, 0x13, 0x57, 0x36, 0xfe, 0x4a, 0xf6, 0xbc, 0xca, 0xd9, 0x34, 0x9b, 0xef, 0x90, 0x02, 0xd9, 0xbd, 0xdd, 0x6f, 0x22, 0x54, 0x36, 0xb2, 0x3f, 0x22, 0x65, 0xef, 0xe7}, {0x04, 0xd4, 0x43, 0xe8, 0x8c, 0xc4, 0xfb, 0xe5, 0x55, 0xd0, 0xa4, 0xea, 0x20, 0xf8, 0xe1, 0x8f, 0xc2, 0xbc, 0x1f, 0x55, 0xf1, 0x8d, 0xda, 0xc0, 0x85, 0xa4, 0xef, 0x36, 0x97, 0x22, 0x8b, 0x8e, 0x77, 0x4c, 0x1a, 0xa4, 0xa0, 0x6f, 0xe1, 0xdc, 0x32, 0x47, 0xc4, 0x3a, 0xd8, 0x8a, 0xbd, 0x19, 0x30, 0x1c, 0x96, 0x7a, 0xb2, 0x23, 0x7c, 0x16, 0x03, 0xa7, 0x4f, 0xfd, 0xa6, 0x50, 0xd9, 0xf7}, {0xdf, 0xc2, 0x59, 0xd2, 0xa9, 0x9b, 0x1e, 0xca, 0xf0, 0x39, 0x2f, 0xf8, 0xc2, 0xf3, 0x91, 0x55, 0x1b, 0xba, 0x81, 0x3a, 0x67, 0x1a, 0xd4, 0xf4, 0xb0, 0x9f, 0xb6, 0x18, 0x38, 0x65, 0x3e, 0x67, 0xa0, 0x37, 0xc2, 0x9a, 0xc7, 0xee, 0x72, 0x8e, 0x13, 0x64, 0xd1, 0x0a, 0xda, 0xbd, 0x8d, 0xa4, 0x28, 0x55, 0x3a, 0x2c, 0x78, 0x41, 0xc6, 0xfc, 0x1c, 0x0f, 0xf8, 0xd7, 0x5f, 0xe6, 0xde, 0x0b, 0xd5, 0xc0, 0xaa, 0x2c, 0x5c, 0xac, 0x46, 0xeb, 0xa4, 0x35, 0x2a, 0xab, 0x00, 0x2e, 0xc0, 0x8b, 0x42, 0x65, 0x2f, 0x2f, 0x13, 0x84, 0x60, 0x15, 0xa3, 0x69, 0xee, 0xab, 0x0e, 0x50, 0xbf, 0x5f}, {0xc1, 0xb0, 0xac, 0x4c, 0xfa, 0x62, 0x52, 0x22, 0xae, 0x8c, 0x94, 0x38, 0xd9, 0x6e, 0x10, 0x94, 0xe7, 0xaa, 0xc0, 0x92, 0x93, 0x06, 0x55, 0xf9, 0x2e, 0xd9, 0x10, 0x4d, 0xcb, 0x82, 0x19, 0x1f, 0x27, 0x16, 0x81, 0xdd, 0xea, 0x7a, 0xa8, 0xce, 0x5a, 0xdd, 0x37, 0x77, 0x24, 0x57, 0xfb, 0x40, 0x3d, 0x1b, 0x48, 0x88, 0xda, 0xce, 0xe8, 0xd2, 0xed, 0xe0, 0x6e, 0x29, 0xeb, 0xdb, 0x95, 0x09, 0xd5, 0xc0, 0xaa, 0x2c, 0x5c, 0xac, 0x46, 0xeb, 0xa4, 0x35, 0x2a, 0xab, 0x00, 0x2e, 0xc0, 0x8b, 0x42, 0x65, 0x2f, 0x2f, 0x13, 0x84, 0x60, 0x15, 0xa3, 0x69, 0xee, 0xab, 0x0e, 0x50, 0xbf, 0x5f}}, - {{0x3a, 0x79, 0x39, 0x60, 0xe9, 0x93, 0xad, 0x78, 0xf9, 0x0b, 0x99, 0x64, 0x71, 0x76, 0xad, 0xdc, 0x63, 0xa3, 0x38, 0xbf, 0x0a, 0x36, 0x22, 0xcf, 0x4f, 0x84, 0x3e, 0x34, 0xaf, 0x0b, 0xd4, 0x5c, 0xc0, 0xa4, 0x01, 0x7c, 0x07, 0xc3, 0xb4, 0xcb, 0xdb, 0x39, 0xdd, 0x39, 0xc7, 0x5c, 0xbd, 0xcf, 0x61, 0x8b, 0x72, 0x74, 0xd6, 0x85, 0xdc, 0x5c, 0x08, 0x93, 0x6d, 0xe6, 0xf1, 0xeb, 0xb9, 0x7c}, {0x71, 0x12, 0x20, 0xbb, 0x37, 0xa6, 0xd8, 0x71, 0xf7, 0x58, 0xaa, 0xbd, 0x30, 0xfb, 0xac, 0x94, 0x62, 0x45, 0xf0, 0x1a, 0xc3, 0x4a, 0x07, 0x78, 0x6d, 0x17, 0xf5, 0x8d, 0x69, 0x3d, 0x2e, 0x15, 0x96, 0x48, 0x1a, 0xb0, 0x7e, 0xdd, 0xf5, 0x2d, 0xe1, 0x56, 0xfc, 0xe9, 0x26, 0x91, 0x51, 0xfe, 0x5e, 0x2a, 0xdc, 0x23, 0x89, 0x09, 0x14, 0xe6, 0x17, 0xa9, 0x14, 0x8c, 0x8c, 0xe8, 0xe3, 0x71}, {0xe4, 0xd0, 0xa7, 0x5a, 0xce, 0x93, 0x1d, 0x55, 0xa2, 0x3d, 0xdd, 0x7e, 0x10, 0x66, 0x6d, 0xc6, 0x5c, 0x87, 0x9f, 0x7a, 0x52, 0x5e, 0x76, 0x3f, 0x09, 0x9e, 0xe5, 0x8e, 0x60, 0x39, 0x5e, 0x3c, 0x28, 0x31, 0xa4, 0x12, 0x39, 0xfd, 0xba, 0xda, 0xc8, 0x59, 0xdd, 0x5b, 0x26, 0x78, 0x8f, 0x33, 0xd2, 0xc8, 0x22, 0x77, 0x49, 0xcf, 0x34, 0x61, 0xbe, 0x7a, 0xa6, 0x31, 0xbe, 0xe5, 0xab, 0xc2}, {0x60, 0xf5, 0x52, 0xbd, 0xb1, 0x9e, 0x06, 0xa3, 0x94, 0xad, 0xe0, 0x82, 0x33, 0x7c, 0x41, 0x17, 0x5b, 0x8a, 0xbc, 0x7c, 0xce, 0xd1, 0x7e, 0xfd, 0x39, 0x17, 0xfd, 0x90, 0x5a, 0x53, 0x89, 0x27, 0x9f, 0x27, 0x7a, 0x08, 0xb2, 0x66, 0xda, 0xb5, 0xbf, 0x3b, 0x80, 0xe2, 0x1a, 0x30, 0x80, 0x45, 0x13, 0xf3, 0x4b, 0x0c, 0x4a, 0xe9, 0x0a, 0x6e, 0xf2, 0x3e, 0xa3, 0x70, 0x3d, 0x89, 0xd3, 0xb2}, {0x23, 0x41, 0x08, 0x8d, 0xa8, 0x0b, 0x6a, 0xe0, 0x65, 0xb1, 0x42, 0x50, 0x49, 0xdd, 0xd3, 0xe8, 0x89, 0x13, 0x7a, 0x04, 0xf0, 0xd6, 0x2f, 0x6e, 0x73, 0xcd, 0xdc, 0x10, 0xbb, 0x02, 0x6b, 0xa2, 0x25, 0x58, 0xa3, 0x08, 0x37, 0x7c, 0x8b, 0x1f, 0x4a, 0x81, 0x38, 0x88, 0xbd, 0xf4, 0x4f, 0x24, 0xe8, 0xd6, 0x9f, 0x2f, 0x13, 0xeb, 0x79, 0x60, 0x80, 0x90, 0x52, 0x6b, 0x8e, 0xed, 0xcb, 0x77}, {0x5b, 0x88, 0x63, 0xaf, 0xf9, 0xe2, 0x44, 0x23, 0xc8, 0x02, 0xe0, 0x22, 0x15, 0x3d, 0x2a, 0xb7, 0x40, 0x76, 0xe8, 0x95, 0xfd, 0xa9, 0xe3, 0x85, 0x94, 0xa3, 0xbb, 0xce, 0x61, 0x19, 0x0d, 0xe2, 0x95, 0xdf, 0x81, 0x11, 0x53, 0x77, 0xcd, 0xf2, 0xd8, 0x4f, 0xbf, 0x19, 0x6a, 0x3d, 0x4b, 0xda, 0xa4, 0x56, 0xa4, 0xcd, 0x9d, 0x4f, 0x52, 0x53, 0x7d, 0xd8, 0xac, 0xe0, 0xfb, 0x9a, 0x71, 0x0c, 0x59, 0xf9, 0x0b, 0x03, 0xf1, 0x7b, 0xaf, 0x33, 0xc3, 0xe5, 0x1e, 0x8d, 0x4f, 0xbe, 0x21, 0xed, 0x6b, 0x15, 0xdd, 0xd2, 0xeb, 0x7c, 0xe4, 0x59, 0x6c, 0xf9, 0x91, 0xc1, 0x3a, 0x3a, 0xb6, 0x2b}, {0x5e, 0x54, 0xe5, 0x1b, 0x3d, 0x2c, 0x00, 0x80, 0xdd, 0xe4, 0x10, 0x50, 0x98, 0xb6, 0x0e, 0x3a, 0xf7, 0xde, 0x67, 0x2c, 0x8e, 0x7b, 0xb4, 0x73, 0x0b, 0xc7, 0x12, 0xb0, 0x66, 0x6b, 0x3b, 0x99, 0xd9, 0x33, 0x78, 0x5f, 0x45, 0xe5, 0xec, 0x15, 0x02, 0xfa, 0x8b, 0x86, 0xfd, 0xe0, 0xb7, 0x84, 0x72, 0xf2, 0x68, 0x5c, 0xd6, 0x2e, 0x37, 0xe9, 0x49, 0x32, 0x2f, 0xcd, 0xcd, 0x1e, 0x99, 0x0f, 0x59, 0xf9, 0x0b, 0x03, 0xf1, 0x7b, 0xaf, 0x33, 0xc3, 0xe5, 0x1e, 0x8d, 0x4f, 0xbe, 0x21, 0xed, 0x6b, 0x15, 0xdd, 0xd2, 0xeb, 0x7c, 0xe4, 0x59, 0x6c, 0xf9, 0x91, 0xc1, 0x3a, 0x3a, 0xb6, 0x2b}}, - {{0xfc, 0xb9, 0x4e, 0x4e, 0x11, 0xfe, 0xe1, 0xc5, 0xc7, 0x49, 0x54, 0xd2, 0x2f, 0x13, 0x34, 0x7c, 0x91, 0x7d, 0x98, 0x43, 0xe4, 0xb7, 0x48, 0xea, 0xe8, 0x26, 0xcb, 0x26, 0x1f, 0xe4, 0x99, 0x10, 0xb9, 0x34, 0xc2, 0xac, 0xa3, 0x2c, 0xbd, 0x9e, 0x80, 0xd4, 0x12, 0x3b, 0xb3, 0xf0, 0x01, 0xae, 0x91, 0x9f, 0xba, 0x77, 0x32, 0x4d, 0x9d, 0xac, 0x1f, 0x8d, 0xad, 0xa7, 0x46, 0x44, 0x85, 0xfb}, {0x65, 0x05, 0x0b, 0xd2, 0x41, 0xd3, 0x58, 0x2a, 0x14, 0xbc, 0x7b, 0x15, 0x4a, 0x6a, 0x6a, 0x18, 0x71, 0x09, 0x25, 0x33, 0xac, 0x73, 0x53, 0xab, 0xd9, 0x0d, 0x8d, 0xdf, 0x95, 0x59, 0x7e, 0x02, 0x4c, 0x03, 0x11, 0x5c, 0xdc, 0x80, 0x19, 0xd5, 0x13, 0x66, 0x7f, 0xf7, 0xd7, 0x23, 0x18, 0x40, 0x84, 0x16, 0x6b, 0x52, 0x82, 0x96, 0x05, 0x1b, 0xfa, 0xcb, 0x4b, 0x77, 0x00, 0x12, 0xa0, 0x28}, {0x13, 0xe0, 0x16, 0x1e, 0x24, 0x24, 0xe9, 0xde, 0x9c, 0x86, 0xa9, 0xcf, 0x02, 0x96, 0xdf, 0x8c, 0x64, 0xcb, 0x3d, 0x7d, 0x8a, 0x2a, 0x73, 0x18, 0x20, 0xc8, 0xb0, 0xac, 0x10, 0xa0, 0x52, 0x0c, 0x6c, 0x17, 0xd9, 0xbd, 0x3c, 0x3e, 0xe5, 0x0c, 0x4a, 0xdb, 0x59, 0xcc, 0x59, 0x15, 0x08, 0x1e, 0xfe, 0xaa, 0xe3, 0xd6, 0xa1, 0x37, 0xd6, 0xd5, 0x6d, 0x8e, 0xcd, 0x57, 0xa9, 0x81, 0xb3, 0x43}, {0x46, 0x28, 0x2b, 0xa0, 0xe5, 0xe3, 0xf0, 0x72, 0xa7, 0xbc, 0x8d, 0xec, 0x45, 0x31, 0x6e, 0xdb, 0xb2, 0x4b, 0x20, 0xbf, 0x64, 0x74, 0x26, 0x70, 0x9b, 0xd6, 0xd3, 0x7f, 0x9f, 0xc1, 0x59, 0x03, 0x2d, 0xda, 0x6f, 0xaa, 0x7c, 0x92, 0xc6, 0xe0, 0xe8, 0xaa, 0x1e, 0x26, 0xf0, 0x1e, 0xcc, 0xef, 0x6d, 0x87, 0x04, 0x3c, 0xed, 0x52, 0x15, 0xb3, 0x9f, 0x01, 0x4e, 0xe3, 0x3c, 0xb6, 0xbb, 0xac}, {0x86, 0x1a, 0x25, 0x8e, 0x41, 0x85, 0xf9, 0xba, 0x98, 0x15, 0xb1, 0xec, 0x50, 0xb4, 0xd0, 0xab, 0x55, 0x54, 0xbb, 0x3b, 0x61, 0xfc, 0x54, 0xf3, 0x09, 0xea, 0xaa, 0x6e, 0xbf, 0x03, 0xc3, 0x58, 0x1d, 0x24, 0xb5, 0xd5, 0x45, 0x5a, 0x7a, 0x14, 0xc3, 0x6a, 0xa9, 0xd8, 0x6f, 0x41, 0xc3, 0xb4, 0x9a, 0x05, 0x71, 0xbc, 0x23, 0x67, 0xc2, 0xa8, 0xf5, 0x7b, 0x69, 0xa5, 0xe1, 0x7a, 0x35, 0x1d}, {0x3b, 0xf5, 0xa8, 0xc0, 0x2a, 0x7d, 0x85, 0x88, 0xd4, 0xf4, 0x26, 0xd3, 0xf4, 0xe3, 0x52, 0x35, 0x37, 0x06, 0x1e, 0x71, 0xc2, 0x3b, 0x7b, 0xeb, 0xf0, 0x07, 0x30, 0x6b, 0x37, 0x31, 0xb9, 0x27, 0xd8, 0x0b, 0x17, 0xae, 0xff, 0xd4, 0x7c, 0x59, 0xd7, 0x2d, 0xea, 0xcb, 0x92, 0x2f, 0x93, 0xc7, 0xd7, 0xc3, 0xaf, 0x75, 0x73, 0x6a, 0x3f, 0x89, 0xe5, 0x13, 0x0c, 0x28, 0x47, 0xf4, 0xa4, 0x07, 0xfb, 0xd9, 0x77, 0xb4, 0x1e, 0xb2, 0x70, 0xca, 0x85, 0x22, 0x58, 0xc6, 0x0b, 0x19, 0xc2, 0xa5, 0xba, 0xc3, 0xc9, 0xb6, 0x4a, 0xdb, 0x7d, 0x4d, 0x66, 0xde, 0xeb, 0x8c, 0x1a, 0x23, 0xb8, 0x4c}, {0x8c, 0x57, 0x0e, 0x9f, 0x0a, 0xb2, 0xf4, 0x07, 0xdd, 0x7b, 0x46, 0xf8, 0xa0, 0xb1, 0x33, 0x4c, 0x2b, 0x1e, 0x1a, 0xe0, 0x28, 0x17, 0x14, 0xba, 0x14, 0x06, 0x40, 0x1f, 0x30, 0x0a, 0x19, 0xcd, 0xe7, 0xca, 0xfb, 0xdb, 0xb9, 0x76, 0xf8, 0x8a, 0x81, 0x3d, 0x03, 0x86, 0x7e, 0x66, 0x75, 0x1d, 0xec, 0xff, 0x6b, 0xa7, 0xea, 0x4c, 0x8c, 0x60, 0xd2, 0x1f, 0x72, 0x11, 0x4c, 0x5d, 0xeb, 0x01, 0xfb, 0xd9, 0x77, 0xb4, 0x1e, 0xb2, 0x70, 0xca, 0x85, 0x22, 0x58, 0xc6, 0x0b, 0x19, 0xc2, 0xa5, 0xba, 0xc3, 0xc9, 0xb6, 0x4a, 0xdb, 0x7d, 0x4d, 0x66, 0xde, 0xeb, 0x8c, 0x1a, 0x23, 0xb8, 0x4c}}, - {{0x05, 0x64, 0x16, 0x53, 0xbb, 0xb2, 0x6e, 0x81, 0xfc, 0xe6, 0xec, 0xc8, 0x0c, 0xc1, 0x75, 0x59, 0x23, 0xe2, 0x4b, 0xd8, 0x6a, 0x70, 0x34, 0x50, 0x37, 0xc6, 0xc2, 0xbd, 0x27, 0xfd, 0xad, 0x4c, 0xee, 0xe4, 0xf7, 0xfc, 0x91, 0x05, 0x48, 0x3c, 0xd4, 0x09, 0x78, 0x00, 0xce, 0x15, 0x37, 0xdc, 0xe7, 0xce, 0x48, 0x09, 0x3e, 0x7f, 0x01, 0x9b, 0x03, 0xc8, 0x2f, 0x9b, 0xe6, 0x42, 0xe1, 0x71}, {0x64, 0xbf, 0x63, 0x91, 0xe5, 0x3e, 0x90, 0x89, 0x96, 0xea, 0x59, 0x51, 0x60, 0x7b, 0x5f, 0xfe, 0x0f, 0x76, 0x86, 0x19, 0x45, 0x82, 0xd9, 0x5e, 0x1a, 0xd1, 0xf6, 0x04, 0xc6, 0xaa, 0x71, 0xda, 0x80, 0xed, 0x75, 0x51, 0xc8, 0x9a, 0x27, 0x09, 0xc3, 0x50, 0xe4, 0x14, 0xa1, 0xc3, 0xf8, 0x3a, 0x6c, 0x84, 0xff, 0x87, 0xd5, 0xf0, 0xb0, 0x3c, 0x5a, 0x57, 0x14, 0x90, 0xc7, 0x31, 0xf8, 0x47}, {0x88, 0x7d, 0xcc, 0x81, 0x2b, 0xbb, 0x7e, 0x96, 0xbe, 0x78, 0xe1, 0xb1, 0xf2, 0xed, 0x6f, 0xd8, 0xff, 0xbd, 0x7f, 0x8e, 0xe5, 0xeb, 0x7f, 0x7b, 0xca, 0xaf, 0x9b, 0x08, 0x1a, 0x77, 0x69, 0x1d, 0xc2, 0xa4, 0x7c, 0x4d, 0xa6, 0x74, 0x8e, 0x33, 0x24, 0xff, 0x43, 0xe1, 0x8c, 0x59, 0xae, 0x5f, 0x95, 0xa4, 0x35, 0x9e, 0x61, 0xb8, 0xcc, 0x4c, 0x87, 0xb9, 0x76, 0x53, 0x20, 0xa3, 0xf3, 0xf5}, {0x13, 0x2a, 0xcc, 0x07, 0xb1, 0x5f, 0xc7, 0xf1, 0x08, 0x0e, 0x7d, 0x7e, 0x26, 0x56, 0xd8, 0x16, 0x9c, 0xae, 0xac, 0xc4, 0xf5, 0x9c, 0x15, 0x67, 0xae, 0xc4, 0xcc, 0x3f, 0xc0, 0xaf, 0x53, 0x28, 0x1f, 0x65, 0x14, 0xe5, 0x7f, 0x0c, 0xf5, 0x7a, 0xe3, 0x93, 0xc1, 0xa3, 0xd1, 0x4a, 0x09, 0x7d, 0x24, 0xab, 0x22, 0xc4, 0xc4, 0xce, 0x85, 0x37, 0x86, 0xa8, 0x9c, 0x39, 0x33, 0xba, 0x1b, 0x83}, {0x6d, 0x3e, 0x92, 0x5a, 0xa8, 0xfa, 0xe6, 0x71, 0x98, 0xa8, 0x82, 0x38, 0xcc, 0xed, 0xd6, 0x92, 0x7e, 0x3e, 0xcb, 0xb2, 0x82, 0x92, 0x7a, 0x56, 0x9e, 0xd6, 0x29, 0x45, 0x42, 0x04, 0x76, 0x82, 0xa5, 0xfc, 0xd9, 0x0c, 0x12, 0x4c, 0x98, 0x04, 0x2a, 0x3a, 0x98, 0x01, 0xb8, 0x62, 0xe8, 0xe6, 0x7c, 0x51, 0xe3, 0x7d, 0x97, 0xf5, 0x45, 0xb4, 0x13, 0xdf, 0x15, 0x68, 0xc3, 0x00, 0x75, 0x40}, {0x7e, 0x89, 0x3d, 0x7c, 0x78, 0x36, 0x3c, 0x85, 0xda, 0xb6, 0x9b, 0x6d, 0xbc, 0x52, 0x7d, 0xc6, 0xaa, 0xfd, 0x90, 0x62, 0xe4, 0xc4, 0x1a, 0x5a, 0x2e, 0xa1, 0x57, 0xd7, 0xda, 0x57, 0xf4, 0x58, 0xc5, 0x23, 0x61, 0x21, 0xe1, 0x93, 0xfa, 0x06, 0x22, 0xed, 0x41, 0x66, 0x24, 0x47, 0xb9, 0xed, 0xc8, 0x84, 0x25, 0x28, 0x39, 0xec, 0xfb, 0x29, 0xa1, 0xcd, 0xe1, 0x9d, 0x02, 0x48, 0x6f, 0x0a, 0xe2, 0x9f, 0x98, 0xfd, 0x3d, 0x18, 0xa1, 0x24, 0x9c, 0xc6, 0x75, 0xb8, 0x99, 0x76, 0x2a, 0xa4, 0x9e, 0xb1, 0x97, 0x2d, 0x1c, 0x99, 0x65, 0x5f, 0x1f, 0xda, 0x14, 0x4f, 0x10, 0x49, 0xf1, 0x7a}, {0x2c, 0xec, 0x27, 0x63, 0xd2, 0x77, 0x14, 0x2d, 0x01, 0x18, 0x10, 0xe0, 0x23, 0x1b, 0xa2, 0x25, 0x61, 0xd4, 0x52, 0xd9, 0x90, 0xde, 0x97, 0x7e, 0xb8, 0xfa, 0x38, 0x25, 0xf2, 0x91, 0x07, 0x3e, 0xc4, 0xa9, 0x3e, 0xb5, 0x67, 0x02, 0x28, 0x94, 0x5c, 0x34, 0xa1, 0x0a, 0x5c, 0x54, 0x53, 0xd9, 0xb4, 0xc4, 0x5a, 0x8e, 0x57, 0x18, 0xc3, 0x35, 0xea, 0x47, 0x75, 0xe0, 0x44, 0x01, 0x71, 0x09, 0xe2, 0x9f, 0x98, 0xfd, 0x3d, 0x18, 0xa1, 0x24, 0x9c, 0xc6, 0x75, 0xb8, 0x99, 0x76, 0x2a, 0xa4, 0x9e, 0xb1, 0x97, 0x2d, 0x1c, 0x99, 0x65, 0x5f, 0x1f, 0xda, 0x14, 0x4f, 0x10, 0x49, 0xf1, 0x7a}}, - {{0x41, 0x10, 0xd9, 0x7f, 0xb8, 0x83, 0x9e, 0x42, 0x43, 0x7a, 0xb0, 0x6d, 0xa6, 0xcf, 0xa5, 0x7a, 0x50, 0x93, 0x2d, 0x13, 0x94, 0x37, 0xa8, 0x92, 0x26, 0x1f, 0xad, 0xe0, 0x25, 0x19, 0x91, 0x62, 0x28, 0xfb, 0x18, 0xbf, 0x89, 0xb0, 0x42, 0x80, 0x14, 0xcd, 0xd2, 0x72, 0x84, 0x1c, 0xfd, 0xe5, 0xc3, 0x71, 0x3c, 0x3f, 0x12, 0x5e, 0xdd, 0x53, 0x39, 0xf6, 0x4b, 0x9f, 0xb3, 0x5c, 0xe3, 0x15}, {0xd0, 0xc7, 0x18, 0x4d, 0x68, 0x9f, 0xdd, 0xec, 0x81, 0xf8, 0xc6, 0x0e, 0x83, 0x43, 0x23, 0x3d, 0xfc, 0xf3, 0x66, 0x55, 0xa8, 0x65, 0x8b, 0xd7, 0x9b, 0x3c, 0x74, 0x23, 0xcd, 0xae, 0x60, 0xe7, 0x61, 0xed, 0x2c, 0x7e, 0xe7, 0xa7, 0x63, 0x7d, 0x72, 0x47, 0x6a, 0x33, 0x1c, 0xaa, 0x81, 0xba, 0x6f, 0xd4, 0x00, 0xe7, 0xa9, 0x58, 0xb2, 0xad, 0xee, 0x3f, 0x9c, 0x70, 0xff, 0x2f, 0x13, 0x6f}, {0x56, 0x7b, 0x19, 0x66, 0x42, 0x9a, 0x99, 0x51, 0x23, 0x4f, 0xb6, 0xe7, 0xcf, 0x98, 0xff, 0x20, 0x5a, 0xc3, 0x0e, 0x36, 0xc9, 0xc6, 0x20, 0x25, 0x0c, 0x56, 0x98, 0xfb, 0xbd, 0xd6, 0x66, 0x4f, 0x6f, 0x94, 0x85, 0x8a, 0x35, 0xf3, 0x50, 0xad, 0x87, 0xde, 0x95, 0x9e, 0xae, 0x2a, 0xd8, 0xdd, 0x78, 0x87, 0x96, 0x2b, 0xe0, 0x12, 0x95, 0xd9, 0x3b, 0xb2, 0x2a, 0x06, 0xe2, 0xf0, 0x06, 0xd4}, {0x42, 0x24, 0xdd, 0x0a, 0xd1, 0x11, 0x31, 0x7e, 0x56, 0x45, 0xb0, 0x0e, 0x86, 0xc1, 0x5d, 0x8c, 0x03, 0x01, 0xb8, 0x33, 0x20, 0xbd, 0x08, 0x10, 0xe5, 0x70, 0x92, 0x2b, 0x5b, 0x86, 0xd3, 0x50, 0x4c, 0x1e, 0xe3, 0xd1, 0x2a, 0x4e, 0x40, 0x02, 0x19, 0x0b, 0xf6, 0x91, 0xd9, 0x9e, 0xaa, 0x54, 0x7c, 0x3d, 0xba, 0xc5, 0x5a, 0x9e, 0xb2, 0xbb, 0x4e, 0x0d, 0x5b, 0xdd, 0x90, 0xc9, 0x7b, 0xc2}, {0x54, 0x95, 0xd5, 0xdc, 0x7e, 0x7e, 0xec, 0xd4, 0x67, 0x08, 0xdc, 0x58, 0xa9, 0x80, 0x8a, 0x03, 0x6a, 0xf8, 0x40, 0xca, 0x0d, 0x5b, 0x6c, 0xe4, 0xc9, 0x71, 0xa5, 0xaf, 0x2a, 0xaa, 0xe8, 0x95, 0x45, 0xe7, 0xe2, 0xc3, 0x47, 0x84, 0xc6, 0xbe, 0xe5, 0x65, 0xaf, 0xcd, 0x7c, 0x20, 0x5f, 0x8b, 0x19, 0x61, 0xe4, 0xc9, 0xc1, 0x86, 0xa5, 0x6f, 0x96, 0xf3, 0x9c, 0x13, 0x28, 0x1b, 0xcf, 0x07}, {0xc4, 0x7f, 0xf2, 0x6f, 0xcc, 0x4a, 0xf8, 0xa4, 0x1f, 0x1d, 0x6e, 0x5e, 0x30, 0xb2, 0x99, 0x8f, 0x5d, 0x7c, 0x26, 0x1c, 0x52, 0x6f, 0xd0, 0x33, 0xa7, 0xf8, 0xca, 0x2a, 0xc3, 0x8c, 0xa8, 0xd1, 0x50, 0x4f, 0xa7, 0xe8, 0xf2, 0x10, 0x4c, 0xcd, 0x8a, 0x31, 0x03, 0xc8, 0x93, 0x2c, 0xd7, 0xe4, 0x21, 0xdb, 0xa2, 0x62, 0x7b, 0x1f, 0x28, 0x14, 0x69, 0x7e, 0x87, 0xac, 0xf9, 0xb4, 0x97, 0x00, 0x62, 0x86, 0x14, 0xd7, 0xe4, 0x65, 0xdd, 0x9e, 0x1c, 0x64, 0x5f, 0x3e, 0xef, 0xfe, 0xa6, 0x60, 0x68, 0x91, 0x94, 0x8a, 0x1c, 0x89, 0xae, 0xe4, 0xcf, 0x3a, 0xdd, 0xc0, 0xb4, 0x47, 0xe8, 0x8f}, {0x12, 0x80, 0x00, 0xda, 0xce, 0xc4, 0x80, 0x8f, 0xa9, 0xa1, 0x5d, 0x98, 0x7d, 0x2c, 0xb2, 0x9c, 0x71, 0xde, 0x62, 0x89, 0x6a, 0xe1, 0x92, 0xd7, 0x96, 0xdc, 0xcd, 0xc8, 0x08, 0x0e, 0x48, 0xbf, 0x2a, 0x53, 0x72, 0x90, 0x31, 0x71, 0x49, 0x02, 0xda, 0x4e, 0x19, 0x05, 0x10, 0xcb, 0x41, 0x97, 0x44, 0xdc, 0x2d, 0x1e, 0x48, 0xe5, 0x0e, 0x41, 0x9d, 0x7d, 0x03, 0xa3, 0xe2, 0x65, 0xd4, 0x01, 0x62, 0x86, 0x14, 0xd7, 0xe4, 0x65, 0xdd, 0x9e, 0x1c, 0x64, 0x5f, 0x3e, 0xef, 0xfe, 0xa6, 0x60, 0x68, 0x91, 0x94, 0x8a, 0x1c, 0x89, 0xae, 0xe4, 0xcf, 0x3a, 0xdd, 0xc0, 0xb4, 0x47, 0xe8, 0x8f}}, - {{0x00, 0x4b, 0x0b, 0xf5, 0x1f, 0x07, 0x1e, 0x23, 0xe3, 0x93, 0x7b, 0x31, 0x41, 0x2a, 0x0a, 0x50, 0x35, 0xe2, 0xbb, 0xfe, 0x51, 0x77, 0x6c, 0xc9, 0xc5, 0x13, 0xb9, 0x87, 0x79, 0x65, 0x68, 0x20, 0xcc, 0x09, 0x90, 0xa9, 0xe4, 0xef, 0x9f, 0x1a, 0xe1, 0x69, 0x76, 0x14, 0x82, 0x42, 0x88, 0x4b, 0xdc, 0xe0, 0x10, 0x22, 0xe2, 0xd6, 0x36, 0x7c, 0x0b, 0xd9, 0x08, 0xea, 0xfa, 0xe4, 0xfd, 0x45}, {0x57, 0x5c, 0x1e, 0x20, 0xb4, 0xae, 0x9e, 0x9d, 0x04, 0xfb, 0x1a, 0xd7, 0x23, 0xd8, 0x8a, 0x6b, 0x1b, 0xb2, 0xef, 0xa9, 0x06, 0x38, 0xbb, 0x9b, 0x43, 0x2e, 0xf1, 0x81, 0x0b, 0x76, 0xec, 0x20, 0x46, 0x1b, 0xc4, 0x71, 0x19, 0x3e, 0x79, 0xe8, 0xcf, 0xea, 0xdc, 0x4b, 0x3f, 0x0b, 0xeb, 0x05, 0x13, 0x1a, 0x2c, 0xfe, 0x16, 0xe9, 0xf0, 0xc4, 0x9c, 0x41, 0xab, 0x45, 0x1b, 0xba, 0x05, 0xec}, {0x06, 0x0b, 0x73, 0xec, 0x30, 0x74, 0x0d, 0x8d, 0x13, 0x4b, 0xef, 0xac, 0x3b, 0x05, 0xb6, 0xed, 0x2b, 0x05, 0xd1, 0xa7, 0x65, 0xb0, 0xcb, 0x69, 0x00, 0xeb, 0x47, 0xe3, 0x1c, 0x07, 0x8b, 0x15, 0xbf, 0x69, 0xff, 0x27, 0xb4, 0xdb, 0x77, 0xaf, 0xe9, 0x9a, 0xfb, 0xb2, 0x28, 0xa4, 0xf9, 0x05, 0xe4, 0x3c, 0x66, 0x56, 0x00, 0x1a, 0x2c, 0x41, 0xf2, 0xe1, 0x11, 0x09, 0xfa, 0xe1, 0x50, 0x49}, {0xbc, 0x4d, 0x6f, 0x75, 0x79, 0x77, 0x64, 0x6b, 0xec, 0xac, 0x1a, 0x26, 0x73, 0x9c, 0xf3, 0xf1, 0x4d, 0x79, 0xbe, 0x6f, 0x0c, 0x07, 0x22, 0xd1, 0xa1, 0x31, 0x75, 0xa8, 0x9c, 0xb6, 0x00, 0x63, 0x0d, 0x40, 0x17, 0xec, 0x83, 0xda, 0x82, 0x2c, 0x3b, 0xfd, 0x90, 0xe3, 0xbc, 0xc2, 0x2c, 0xf5, 0x3e, 0x41, 0xe9, 0x98, 0x57, 0xa2, 0xb7, 0xce, 0x5f, 0x31, 0xbb, 0x0b, 0x05, 0x61, 0x0f, 0x55}, {0xb7, 0xab, 0xb2, 0x84, 0xf1, 0x67, 0x24, 0x16, 0x61, 0xe9, 0x20, 0x33, 0x0b, 0xff, 0x22, 0x61, 0x70, 0xa0, 0x5d, 0xf6, 0xa8, 0x33, 0xc9, 0x30, 0x73, 0xe5, 0x89, 0x36, 0x59, 0xea, 0xa8, 0xe7, 0x03, 0xf6, 0x14, 0xc1, 0x79, 0xb6, 0x42, 0xa5, 0xc8, 0x6c, 0xb8, 0x94, 0x29, 0x24, 0x00, 0x09, 0xb5, 0x54, 0x3f, 0xe1, 0x6b, 0xfb, 0x4d, 0x2d, 0xa9, 0x9a, 0x02, 0xa1, 0xa5, 0x09, 0xf4, 0xcb}, {0x92, 0xfa, 0x18, 0x84, 0x3e, 0xdb, 0xdf, 0x7d, 0x87, 0xd6, 0x2d, 0x07, 0x05, 0x2c, 0xba, 0xe4, 0x30, 0x76, 0xa2, 0xe8, 0x71, 0x3b, 0x1b, 0x93, 0x5b, 0xce, 0x2e, 0xec, 0x50, 0x6e, 0x4a, 0x0b, 0x2d, 0xbe, 0xa3, 0x76, 0x92, 0xf8, 0xc8, 0x4a, 0x71, 0x66, 0xec, 0xfa, 0x36, 0xc5, 0xdb, 0xab, 0x99, 0x9c, 0xbf, 0x99, 0x07, 0xe8, 0xfe, 0xf4, 0x2f, 0x90, 0x16, 0x5d, 0xdc, 0xbe, 0xfa, 0x08, 0x93, 0xde, 0x13, 0xf5, 0x32, 0x45, 0x9a, 0xde, 0xa2, 0x5d, 0xb9, 0xe0, 0x38, 0x4c, 0x6a, 0xcc, 0x13, 0x46, 0x27, 0x28, 0xbf, 0xf8, 0x7a, 0x9c, 0x2e, 0xde, 0x6f, 0xfe, 0xe1, 0x86, 0x41, 0x79}, {0xa7, 0x32, 0x52, 0x76, 0x4f, 0x3e, 0x1b, 0xab, 0x82, 0x18, 0x14, 0xe7, 0x42, 0x32, 0xb8, 0xa4, 0x98, 0xde, 0xa4, 0xd7, 0xae, 0x42, 0x84, 0xda, 0x71, 0xf7, 0x78, 0x40, 0x56, 0x94, 0x64, 0x49, 0x34, 0x37, 0xeb, 0xe3, 0x05, 0x4c, 0xb9, 0xbb, 0xce, 0xb2, 0x72, 0xc0, 0x75, 0x1c, 0xc4, 0xd5, 0x1e, 0x3a, 0xc1, 0x43, 0xda, 0xd1, 0x81, 0x82, 0xa9, 0xd5, 0x0e, 0x0a, 0x5e, 0xc2, 0xd7, 0x04, 0x93, 0xde, 0x13, 0xf5, 0x32, 0x45, 0x9a, 0xde, 0xa2, 0x5d, 0xb9, 0xe0, 0x38, 0x4c, 0x6a, 0xcc, 0x13, 0x46, 0x27, 0x28, 0xbf, 0xf8, 0x7a, 0x9c, 0x2e, 0xde, 0x6f, 0xfe, 0xe1, 0x86, 0x41, 0x79}}, - {{0xa3, 0xdf, 0x4a, 0xfd, 0xe6, 0x74, 0xb8, 0xeb, 0xed, 0xe7, 0x7e, 0xd2, 0xae, 0xf8, 0x40, 0x80, 0x3a, 0x55, 0x58, 0x1d, 0x6b, 0xa4, 0x32, 0x6c, 0x15, 0xbb, 0x67, 0xdf, 0x9e, 0xb5, 0x70, 0x4b, 0x7f, 0x4d, 0xfe, 0x34, 0x42, 0x0c, 0x4d, 0xe3, 0x97, 0x87, 0x6d, 0x08, 0xe8, 0x4d, 0x8a, 0xa9, 0xbc, 0xbf, 0x1b, 0xb7, 0x66, 0x32, 0xf4, 0x7f, 0x93, 0xca, 0xa4, 0xd2, 0x8f, 0x02, 0x7b, 0xfa}, {0xea, 0xac, 0xdf, 0x25, 0x39, 0xf3, 0x28, 0xb6, 0xbe, 0xa8, 0x4a, 0x32, 0x59, 0x4b, 0x4f, 0xb5, 0xd2, 0xf7, 0xf5, 0x75, 0x43, 0x8b, 0xb3, 0x6a, 0x98, 0x8c, 0x14, 0xc9, 0x3f, 0x7e, 0x5c, 0x05, 0xf0, 0xeb, 0x1d, 0xc5, 0xe6, 0x1b, 0x5d, 0x7f, 0x38, 0x5d, 0x9a, 0xbe, 0xc8, 0x97, 0x09, 0x65, 0x62, 0x88, 0x99, 0xda, 0x95, 0x13, 0x93, 0xd9, 0xa3, 0x19, 0x0a, 0xa7, 0x4a, 0xb2, 0x81, 0xa4}, {0x6e, 0x70, 0x65, 0xaa, 0x1b, 0x16, 0xcb, 0xc1, 0x59, 0x6b, 0xc9, 0x4d, 0xd1, 0x0a, 0x9d, 0x8c, 0x76, 0x70, 0x3c, 0xc1, 0xc1, 0x66, 0xa6, 0x9f, 0xfc, 0xca, 0xb0, 0x3f, 0x0e, 0xe9, 0xa9, 0x36, 0x09, 0x4f, 0x94, 0xf3, 0x32, 0x25, 0x34, 0xf6, 0xe4, 0xf9, 0x0b, 0x0c, 0xe6, 0xe0, 0x6d, 0x9e, 0xa5, 0x52, 0x82, 0x9c, 0xd4, 0x43, 0xa4, 0xd1, 0xd1, 0x63, 0x20, 0xce, 0xbc, 0x4f, 0x43, 0xdc}, {0x35, 0xd6, 0xc1, 0x68, 0xa6, 0xd7, 0xd3, 0x36, 0x82, 0x2a, 0x0f, 0x29, 0x3e, 0xd6, 0x15, 0x29, 0x19, 0x73, 0x14, 0x78, 0x87, 0x86, 0xca, 0x9f, 0x6e, 0x17, 0xea, 0xaf, 0x24, 0x37, 0xd6, 0xb4, 0xb0, 0xee, 0x84, 0x90, 0x2d, 0x18, 0xbd, 0x26, 0xc3, 0xd4, 0x39, 0x4f, 0x45, 0xfa, 0x2f, 0x70, 0xf2, 0xe2, 0x2a, 0x2a, 0x5c, 0x65, 0x15, 0xcb, 0xaf, 0x92, 0x9a, 0xfc, 0x06, 0xe0, 0x8a, 0x1b}, {0x5d, 0xfa, 0xc0, 0x2b, 0xc3, 0x94, 0x19, 0xb4, 0xd6, 0x13, 0xe3, 0xcf, 0x91, 0xad, 0x8c, 0xe1, 0x97, 0x46, 0xfe, 0xea, 0x74, 0xe0, 0x0c, 0x03, 0xf7, 0x2e, 0x51, 0xa7, 0xf2, 0xbc, 0xce, 0xe8, 0x6b, 0xfd, 0x2f, 0x54, 0x52, 0x12, 0x00, 0x8d, 0x95, 0x91, 0xc3, 0xf6, 0x25, 0xf8, 0x65, 0x6a, 0x9c, 0x79, 0x6b, 0x71, 0xc0, 0x0c, 0x29, 0xfb, 0xe7, 0x14, 0x9f, 0x2f, 0x1a, 0x07, 0x53, 0x50}, {0xe9, 0xd4, 0x46, 0x0b, 0x51, 0x3f, 0xf1, 0xbe, 0x0a, 0x23, 0xa5, 0x38, 0xa0, 0xe3, 0x70, 0x14, 0x63, 0xf0, 0x94, 0xbb, 0x1c, 0x4f, 0x23, 0x05, 0x1b, 0x62, 0x40, 0x9b, 0xf9, 0x52, 0x1b, 0x41, 0x51, 0x57, 0x2a, 0x99, 0x73, 0xda, 0xe1, 0xcf, 0xc5, 0x4c, 0x65, 0x3a, 0xc2, 0x9d, 0x73, 0xda, 0xc9, 0x59, 0xf1, 0xdf, 0xab, 0x2b, 0x27, 0xe1, 0x59, 0x8b, 0xa7, 0x48, 0xf9, 0x36, 0xcb, 0x08, 0xe3, 0x5e, 0x1d, 0xdd, 0xf9, 0x20, 0x4f, 0x64, 0xa9, 0x26, 0x74, 0x97, 0xf2, 0x2d, 0x31, 0xac, 0x8c, 0x20, 0x77, 0x09, 0xa9, 0x8f, 0xed, 0x23, 0x77, 0x7e, 0xd7, 0x34, 0x93, 0x84, 0xe7, 0xaa}, {0xaa, 0xf7, 0x64, 0xdf, 0x34, 0x59, 0x1c, 0x2c, 0xbc, 0x47, 0x08, 0x6a, 0x25, 0xbf, 0x9d, 0x48, 0x54, 0xcf, 0xa0, 0x6c, 0xfc, 0xd4, 0x10, 0x39, 0x9f, 0x64, 0x46, 0xce, 0xd9, 0x95, 0x28, 0x89, 0xdf, 0x94, 0x5e, 0x74, 0x0b, 0x55, 0x46, 0x82, 0xd9, 0x3d, 0x82, 0x97, 0x7d, 0xd0, 0x3e, 0xd7, 0xf6, 0x6f, 0xaa, 0x97, 0x3e, 0xdf, 0xa7, 0xde, 0xe3, 0xc5, 0xaf, 0xd3, 0xa0, 0x5a, 0x30, 0x0d, 0xe3, 0x5e, 0x1d, 0xdd, 0xf9, 0x20, 0x4f, 0x64, 0xa9, 0x26, 0x74, 0x97, 0xf2, 0x2d, 0x31, 0xac, 0x8c, 0x20, 0x77, 0x09, 0xa9, 0x8f, 0xed, 0x23, 0x77, 0x7e, 0xd7, 0x34, 0x93, 0x84, 0xe7, 0xaa}}, - {{0x96, 0x4e, 0xf2, 0x1e, 0x3a, 0xe5, 0x77, 0xbf, 0xa7, 0x1c, 0x3d, 0x66, 0x08, 0x06, 0xca, 0x55, 0x43, 0x7a, 0x08, 0xf8, 0xff, 0x55, 0xb3, 0xbc, 0x9a, 0x83, 0x9a, 0x2e, 0xe6, 0x97, 0x14, 0x32, 0x36, 0x57, 0x5c, 0xa4, 0x04, 0x78, 0xb1, 0x92, 0xf4, 0x23, 0x94, 0xe6, 0x2a, 0xef, 0xd4, 0xe7, 0xc4, 0x02, 0x9f, 0xa9, 0x79, 0x77, 0x61, 0x90, 0xd6, 0xdb, 0x6e, 0x28, 0x7e, 0xc0, 0x1d, 0x70}, {0xc5, 0xd1, 0x5c, 0x34, 0x15, 0xa9, 0x1e, 0x42, 0x2a, 0x1b, 0x0d, 0xf0, 0x56, 0x83, 0x10, 0xc3, 0xc9, 0x21, 0xfd, 0x05, 0xfa, 0x51, 0x0e, 0x11, 0x28, 0xcc, 0x84, 0xac, 0x35, 0xb5, 0xd8, 0xc8, 0x5c, 0x80, 0x11, 0x1f, 0x60, 0x1c, 0x72, 0x25, 0x82, 0x45, 0xb5, 0x4f, 0x66, 0x6b, 0x52, 0xb1, 0xf7, 0x28, 0x0f, 0x80, 0x76, 0x44, 0xdc, 0x15, 0x70, 0x39, 0xe9, 0xaf, 0xc7, 0x0a, 0xa0, 0x43}, {0xff, 0x20, 0x5e, 0x3b, 0x75, 0xe9, 0x38, 0x7c, 0xa3, 0x5c, 0x8b, 0x1a, 0xec, 0x17, 0x8d, 0xf0, 0xef, 0xb3, 0x53, 0x9b, 0x16, 0xa9, 0x44, 0xf9, 0x34, 0x45, 0x13, 0x66, 0x80, 0x24, 0xdc, 0x22, 0x0e, 0x51, 0x94, 0xed, 0xe6, 0x83, 0x36, 0x32, 0x63, 0x23, 0x1b, 0xf8, 0x78, 0xb4, 0x04, 0x7f, 0x5a, 0x50, 0x54, 0x12, 0x19, 0x04, 0x61, 0xdd, 0x25, 0xf0, 0x48, 0x29, 0x04, 0xc1, 0x44, 0xe2}, {0x46, 0x32, 0x2d, 0xc7, 0xbc, 0x05, 0x2a, 0xd3, 0xb5, 0xce, 0x7d, 0x47, 0x5e, 0xfc, 0x90, 0x38, 0xef, 0xfa, 0x6f, 0x42, 0xf0, 0x66, 0x05, 0x89, 0x7c, 0x9a, 0xc1, 0xfd, 0xa2, 0xe8, 0xa7, 0x38, 0x18, 0x6d, 0x7f, 0x9e, 0xfb, 0xbd, 0x06, 0x0c, 0x70, 0xd7, 0x29, 0x10, 0x88, 0x04, 0x9f, 0x24, 0x28, 0x9d, 0xc7, 0x84, 0xdf, 0xb6, 0xec, 0xb2, 0xc7, 0x1b, 0xd1, 0xc1, 0x9d, 0x56, 0xb0, 0x83}, {0xda, 0xd7, 0x34, 0xee, 0x62, 0x13, 0x8f, 0x47, 0xad, 0xb4, 0x9c, 0x98, 0xe4, 0xc5, 0xb3, 0x29, 0x31, 0x11, 0x64, 0xad, 0xf5, 0x0b, 0x60, 0xe1, 0x0e, 0x18, 0x28, 0x30, 0x3c, 0xa2, 0xe3, 0x29, 0x89, 0x0a, 0x7e, 0x18, 0xba, 0x30, 0x9e, 0x7d, 0x53, 0xf1, 0x82, 0xd5, 0x27, 0xe5, 0xf3, 0xab, 0x15, 0xcd, 0x62, 0x7e, 0xdf, 0xf0, 0x0e, 0x42, 0xfa, 0x6b, 0x7b, 0x54, 0xd2, 0x74, 0x19, 0x8f}, {0x29, 0x4d, 0x28, 0x80, 0x62, 0xb5, 0x77, 0xbb, 0x69, 0x70, 0xb0, 0xb7, 0x10, 0x2e, 0xed, 0xfc, 0x13, 0x34, 0x93, 0x7f, 0xd8, 0xfc, 0xb5, 0x7b, 0xfe, 0x34, 0x0a, 0xa3, 0x95, 0x5b, 0xb1, 0xa7, 0xc6, 0xab, 0x82, 0x79, 0x25, 0x23, 0x94, 0x12, 0xa4, 0x34, 0xec, 0x23, 0xca, 0xcb, 0xd0, 0xa3, 0xf9, 0x31, 0x32, 0xce, 0x50, 0x31, 0x73, 0x23, 0x98, 0x94, 0xe3, 0x08, 0xd9, 0x1e, 0xc3, 0x0b, 0x39, 0xe3, 0x3b, 0xf2, 0xe8, 0xb7, 0x26, 0x28, 0x9d, 0xb3, 0x12, 0x8d, 0x16, 0xca, 0x89, 0x26, 0xa9, 0x1c, 0xa3, 0x1f, 0x36, 0x10, 0x60, 0x6a, 0x29, 0x85, 0xe7, 0x2c, 0xee, 0xc1, 0xb6, 0xae}, {0x68, 0xed, 0x3c, 0x64, 0xe6, 0x87, 0xf0, 0x14, 0x64, 0xfc, 0x38, 0x3a, 0x0f, 0xd9, 0x7a, 0x5b, 0x52, 0x32, 0x10, 0xca, 0xc6, 0x83, 0x0b, 0xae, 0x17, 0x0e, 0xfe, 0x77, 0xe0, 0xe7, 0x83, 0xa1, 0x2c, 0x78, 0x62, 0x9c, 0x79, 0x08, 0x2b, 0xd4, 0x85, 0x72, 0x27, 0x8d, 0x97, 0x78, 0x62, 0x33, 0x34, 0xeb, 0x5c, 0xde, 0x5d, 0xaa, 0x4d, 0xfa, 0xd1, 0x67, 0xa4, 0xea, 0x45, 0xad, 0xf9, 0x06, 0x39, 0xe3, 0x3b, 0xf2, 0xe8, 0xb7, 0x26, 0x28, 0x9d, 0xb3, 0x12, 0x8d, 0x16, 0xca, 0x89, 0x26, 0xa9, 0x1c, 0xa3, 0x1f, 0x36, 0x10, 0x60, 0x6a, 0x29, 0x85, 0xe7, 0x2c, 0xee, 0xc1, 0xb6, 0xae}}, - {{0xd9, 0x64, 0xb2, 0xe1, 0x9f, 0x0a, 0x35, 0xfc, 0x9f, 0xc3, 0xa5, 0x2a, 0xa3, 0x84, 0xb4, 0xf3, 0x23, 0xc4, 0xf3, 0x5a, 0x9d, 0xf8, 0x7f, 0x35, 0xa9, 0xf5, 0x5b, 0x68, 0xfc, 0x19, 0x69, 0x63, 0x6a, 0x13, 0x19, 0x32, 0xcc, 0x9d, 0x0c, 0x3c, 0x7d, 0xdd, 0x85, 0x16, 0xa8, 0xd9, 0x2b, 0x75, 0x08, 0x4b, 0x9a, 0xa5, 0x6e, 0xf3, 0xe9, 0xeb, 0xed, 0x5d, 0x2e, 0xfd, 0x2e, 0x0c, 0x60, 0xa2}, {0x0f, 0xf6, 0x8c, 0x3f, 0x6e, 0xee, 0x56, 0x4f, 0x43, 0x6f, 0x54, 0xbd, 0x7a, 0xe4, 0xbe, 0xa8, 0x77, 0x05, 0x99, 0xe7, 0x9e, 0x59, 0x22, 0x85, 0x9b, 0xc6, 0xe4, 0x2a, 0x61, 0x9c, 0x19, 0xb1, 0x5a, 0xeb, 0x7a, 0xf8, 0x41, 0x4e, 0xe5, 0x2a, 0xd0, 0xf7, 0x44, 0xf0, 0x16, 0xea, 0x0c, 0x04, 0x19, 0x6c, 0xb6, 0x30, 0x3c, 0x6e, 0x2d, 0x79, 0x9a, 0x8f, 0x08, 0x90, 0x11, 0xf1, 0xc0, 0x4d}, {0x68, 0xe7, 0x1d, 0x40, 0xf1, 0x07, 0xc0, 0xc6, 0xb2, 0x87, 0x9c, 0xa2, 0x19, 0x43, 0x7a, 0xdf, 0x8a, 0x5a, 0x0f, 0xe2, 0x24, 0x97, 0xa0, 0x38, 0x79, 0x20, 0x38, 0xa9, 0x9c, 0x77, 0xc4, 0x37, 0xa6, 0x02, 0xe0, 0x93, 0x47, 0xa4, 0x55, 0x21, 0xc2, 0x69, 0xbe, 0x09, 0x05, 0xaa, 0x87, 0x28, 0xf1, 0x95, 0x2f, 0xdb, 0xf0, 0xbf, 0xd2, 0x9e, 0x5e, 0x3a, 0xfa, 0xc6, 0x2f, 0x13, 0x09, 0xaf}, {0xe1, 0x9e, 0xc8, 0x4f, 0xc9, 0xdd, 0x61, 0x60, 0x94, 0xbc, 0xd3, 0xd6, 0xde, 0x11, 0x6e, 0xec, 0x84, 0xc4, 0xdd, 0xbe, 0x20, 0x46, 0x6c, 0xef, 0xf6, 0x9d, 0x37, 0x07, 0x53, 0x72, 0x57, 0xf9, 0x02, 0xb5, 0x64, 0x1f, 0xe2, 0x56, 0xa4, 0x38, 0x6d, 0xa4, 0xed, 0x23, 0x9e, 0xa3, 0xf4, 0x4d, 0x77, 0x52, 0xdc, 0x8c, 0x51, 0xfc, 0x88, 0x18, 0xbc, 0x83, 0x2a, 0xac, 0xc1, 0x1d, 0x3d, 0x59}, {0x08, 0x4f, 0x78, 0x21, 0xfd, 0x4b, 0x85, 0x86, 0x4e, 0x25, 0xdd, 0x47, 0x60, 0x7f, 0x7e, 0xc6, 0xd3, 0xa1, 0xab, 0x91, 0x3f, 0xeb, 0xf6, 0x40, 0x7e, 0x1b, 0xbd, 0x99, 0x9c, 0x7c, 0x2f, 0x4f, 0xca, 0x68, 0xa5, 0xf6, 0x8c, 0x1e, 0xcb, 0xb8, 0x76, 0xe2, 0x87, 0x5b, 0x49, 0x68, 0x97, 0x2c, 0x21, 0x5c, 0x7c, 0x93, 0x79, 0x9a, 0x95, 0xa1, 0x3a, 0x49, 0xc9, 0x6d, 0x34, 0x6b, 0xa1, 0x98}, {0xb9, 0x88, 0x25, 0x9a, 0x3b, 0x53, 0x56, 0xa1, 0x48, 0x0f, 0xf0, 0x92, 0xde, 0x4e, 0x3e, 0x3a, 0xcf, 0x02, 0xdc, 0x5c, 0xc2, 0xc3, 0x78, 0xad, 0x8a, 0x0c, 0x3c, 0xc7, 0xdd, 0xdd, 0x71, 0x6e, 0x3f, 0xd9, 0x3a, 0x57, 0x2a, 0x19, 0xa5, 0x3b, 0x5c, 0x46, 0x7b, 0xc9, 0x0f, 0x16, 0xb3, 0x58, 0xa6, 0x85, 0xfa, 0x91, 0x2c, 0x9a, 0x9c, 0x12, 0xb6, 0xd6, 0x7d, 0x9a, 0xf0, 0x9d, 0xe9, 0x02, 0xad, 0x12, 0x87, 0xda, 0x85, 0x58, 0x6b, 0xff, 0x68, 0x96, 0x05, 0x33, 0xba, 0x7f, 0x08, 0xf9, 0xa9, 0xa2, 0xa9, 0x46, 0x43, 0xe5, 0x03, 0x12, 0xe4, 0xbe, 0x74, 0xaa, 0x46, 0x4e, 0x51, 0xb3}, {0x61, 0x70, 0x17, 0x50, 0x26, 0xfa, 0x51, 0x83, 0xe0, 0xca, 0xa9, 0xb1, 0xc3, 0xc4, 0x83, 0xa9, 0xb6, 0x43, 0x6b, 0x7a, 0x5b, 0xe4, 0x21, 0x5a, 0x6b, 0xd4, 0x34, 0xf8, 0xee, 0x95, 0x86, 0x2d, 0x03, 0xbf, 0xca, 0xd0, 0xfa, 0x68, 0x53, 0xb2, 0x97, 0x50, 0xad, 0x89, 0x2f, 0x99, 0x63, 0x67, 0x18, 0x57, 0x1f, 0x57, 0x41, 0xbc, 0xb7, 0xc0, 0x18, 0xe7, 0xb6, 0xf3, 0x0f, 0xc4, 0x49, 0x0d, 0xad, 0x12, 0x87, 0xda, 0x85, 0x58, 0x6b, 0xff, 0x68, 0x96, 0x05, 0x33, 0xba, 0x7f, 0x08, 0xf9, 0xa9, 0xa2, 0xa9, 0x46, 0x43, 0xe5, 0x03, 0x12, 0xe4, 0xbe, 0x74, 0xaa, 0x46, 0x4e, 0x51, 0xb3}}, - {{0xc5, 0xdf, 0x86, 0x8f, 0xf1, 0xa7, 0xad, 0x57, 0xfd, 0xb4, 0x53, 0xc3, 0x92, 0x1b, 0x9e, 0x2e, 0xdd, 0xc5, 0xa4, 0x3b, 0x72, 0xa6, 0x9b, 0x4a, 0x15, 0xca, 0x35, 0xed, 0x3c, 0x1a, 0x3b, 0x38, 0x36, 0xd6, 0xf2, 0x03, 0xb6, 0x97, 0x1f, 0xcb, 0x40, 0x5d, 0x3c, 0x25, 0xfc, 0xe7, 0xff, 0xc6, 0xbe, 0x61, 0xe1, 0x98, 0x31, 0x13, 0xa9, 0xbe, 0x05, 0x86, 0xfe, 0x5c, 0xf6, 0xcc, 0xaa, 0xf5}, {0xd2, 0x57, 0x19, 0x98, 0xf8, 0x74, 0x90, 0xb7, 0x69, 0x6e, 0xdd, 0x44, 0xf1, 0x8b, 0xb1, 0x9c, 0xfd, 0x5b, 0x6b, 0xc0, 0x45, 0xf2, 0x49, 0xa5, 0x4b, 0xff, 0x8b, 0x7f, 0x87, 0xe3, 0xf9, 0x71, 0xab, 0xfa, 0xc8, 0x17, 0xed, 0xeb, 0x19, 0xc6, 0x3c, 0xee, 0x78, 0xba, 0x89, 0x97, 0x49, 0x85, 0x39, 0x68, 0x29, 0x88, 0x0b, 0x1c, 0xd1, 0x42, 0x8b, 0xe8, 0x1a, 0x3b, 0xeb, 0x4d, 0xef, 0x3b}, {0xea, 0xfb, 0xec, 0x27, 0xc3, 0x92, 0xc3, 0x68, 0x0d, 0x3c, 0x5b, 0x20, 0x20, 0x9c, 0x96, 0xa7, 0x39, 0xfa, 0x80, 0x91, 0xef, 0x86, 0x7d, 0xa8, 0x87, 0xf6, 0xef, 0x14, 0x01, 0x46, 0xf0, 0x68, 0x0a, 0x8b, 0xae, 0x83, 0x91, 0x7e, 0xa0, 0x14, 0x14, 0xde, 0xf9, 0xa8, 0xfd, 0x67, 0x57, 0x17, 0x20, 0x46, 0x43, 0x49, 0x07, 0xf0, 0x3e, 0xc8, 0xbe, 0x66, 0xaf, 0x58, 0x3a, 0xbd, 0xd8, 0x00}, {0x35, 0xf5, 0xc8, 0x2c, 0x0e, 0x4b, 0x56, 0xe0, 0xef, 0x08, 0x34, 0x38, 0x57, 0xe9, 0xde, 0xdb, 0x1d, 0xe1, 0x28, 0x05, 0x01, 0xed, 0x62, 0x3d, 0xa9, 0x6e, 0xea, 0x5b, 0x95, 0x09, 0xe0, 0x04, 0x46, 0xff, 0xdc, 0x34, 0xf6, 0xf7, 0x63, 0xb1, 0x76, 0xb8, 0x3c, 0x03, 0xef, 0x36, 0x0f, 0x82, 0x1b, 0x5b, 0x6f, 0xe2, 0x86, 0xd9, 0x10, 0x01, 0xe6, 0x73, 0x75, 0x0d, 0x50, 0x30, 0x11, 0x68}, {0x27, 0xb6, 0x3b, 0x78, 0x79, 0xf3, 0x22, 0x78, 0x8f, 0x0c, 0x14, 0x8b, 0x3f, 0x68, 0xc2, 0xab, 0x9f, 0x9f, 0x05, 0x70, 0x7e, 0xee, 0x4b, 0x1b, 0x6b, 0xfc, 0x04, 0x72, 0xca, 0xf1, 0x9a, 0xba, 0xe3, 0x65, 0x9d, 0xdb, 0x01, 0x33, 0xc5, 0xdb, 0xf6, 0x87, 0xe4, 0x73, 0x5a, 0x0f, 0x94, 0xa9, 0x2e, 0xfe, 0x8f, 0x3e, 0xd1, 0x0a, 0x6d, 0xa1, 0x21, 0x2a, 0x92, 0x8c, 0x4b, 0x43, 0x13, 0x2f}, {0xa3, 0xa8, 0x3b, 0xb4, 0x4f, 0x8a, 0xac, 0xab, 0x8a, 0x4c, 0x39, 0x7e, 0xb8, 0x2f, 0xb1, 0x01, 0x2e, 0xbe, 0x0e, 0x7d, 0x28, 0x8a, 0x18, 0x4a, 0xda, 0x58, 0x1a, 0xfb, 0x95, 0x97, 0xf3, 0x63, 0x58, 0xbe, 0x8c, 0x30, 0x13, 0x9b, 0xba, 0x9f, 0x4e, 0xac, 0x8d, 0x95, 0xf2, 0x07, 0xbb, 0x85, 0xa1, 0x41, 0x4c, 0x33, 0xe3, 0x58, 0x8e, 0x5c, 0xa1, 0x05, 0x45, 0xab, 0x5c, 0x0c, 0xe4, 0x02, 0xc3, 0xa0, 0xa0, 0x72, 0xdb, 0x9a, 0x9d, 0xbf, 0x13, 0x29, 0x94, 0x70, 0x8b, 0xe4, 0xe8, 0xdb, 0x0e, 0x0b, 0xd0, 0xa0, 0x25, 0xad, 0x71, 0xa0, 0x27, 0x9c, 0x1d, 0x77, 0xb0, 0x98, 0xa8, 0x03}, {0xe1, 0x84, 0xa5, 0xea, 0xa5, 0xd8, 0x1b, 0x29, 0xce, 0xd7, 0xa3, 0x72, 0xa7, 0xc9, 0xa5, 0xea, 0xf1, 0x02, 0xf3, 0x0c, 0xb0, 0x65, 0x12, 0xbc, 0xa4, 0xf2, 0x5d, 0x69, 0x00, 0xa4, 0x7f, 0x5a, 0x52, 0x09, 0xb6, 0x7b, 0x30, 0xf2, 0x99, 0x03, 0x39, 0x9d, 0xee, 0x6f, 0xb5, 0xf7, 0x9e, 0x7a, 0x97, 0x8b, 0x81, 0x03, 0x8c, 0xdd, 0x35, 0xfc, 0x1f, 0x0a, 0xc6, 0xa4, 0x60, 0x7b, 0xc8, 0x0a, 0xc3, 0xa0, 0xa0, 0x72, 0xdb, 0x9a, 0x9d, 0xbf, 0x13, 0x29, 0x94, 0x70, 0x8b, 0xe4, 0xe8, 0xdb, 0x0e, 0x0b, 0xd0, 0xa0, 0x25, 0xad, 0x71, 0xa0, 0x27, 0x9c, 0x1d, 0x77, 0xb0, 0x98, 0xa8, 0x03}}, - {{0x67, 0xe9, 0x62, 0x76, 0x3a, 0x90, 0x9b, 0x6b, 0x19, 0x1d, 0x65, 0xb2, 0x2a, 0x2f, 0xf7, 0x50, 0xaa, 0x54, 0xa5, 0xbb, 0x53, 0xb5, 0xf9, 0xee, 0x0c, 0x04, 0x3a, 0x3c, 0x29, 0x4b, 0x66, 0x3e, 0x7b, 0xb6, 0xaa, 0xd2, 0x10, 0x89, 0xcc, 0x89, 0x2c, 0x47, 0xbe, 0x23, 0xd6, 0x52, 0x81, 0x5d, 0xc8, 0xbc, 0x49, 0xd6, 0x6a, 0xcd, 0x62, 0x99, 0x30, 0xff, 0x16, 0xa5, 0x50, 0x44, 0xd8, 0x7a}, {0xd6, 0xcd, 0xfe, 0xd4, 0x44, 0x4a, 0x9e, 0x90, 0x44, 0x73, 0x8a, 0xff, 0xbb, 0x82, 0x08, 0xb6, 0x7f, 0xf2, 0x87, 0xcb, 0xa5, 0x0b, 0x56, 0xd3, 0x9e, 0x91, 0xb8, 0x52, 0x6b, 0x25, 0xa6, 0x5d, 0x50, 0xaf, 0x9b, 0xd5, 0xfb, 0x9f, 0x7e, 0x2d, 0x57, 0xdf, 0x30, 0x78, 0x8d, 0x1a, 0xc3, 0xac, 0x9c, 0x5a, 0xbf, 0xab, 0x5a, 0x0d, 0xc9, 0xb6, 0x4b, 0x18, 0xd4, 0xe7, 0x55, 0x40, 0xde, 0x7e}, {0xc2, 0xa9, 0x7e, 0x5c, 0x26, 0xf4, 0x7d, 0xce, 0x9e, 0x73, 0xae, 0x50, 0xde, 0xe7, 0xa6, 0xf9, 0x8b, 0x57, 0xf9, 0x7a, 0x4c, 0x38, 0x82, 0xf6, 0x30, 0x80, 0x12, 0xf7, 0xf6, 0x66, 0x80, 0x46, 0x4d, 0x41, 0x53, 0x63, 0xd9, 0x65, 0x90, 0xe7, 0xee, 0x24, 0x07, 0xb0, 0x4f, 0xeb, 0x3e, 0x8e, 0x83, 0x21, 0xa3, 0x40, 0x03, 0xc0, 0x64, 0x52, 0xc6, 0xb2, 0x12, 0x9d, 0x8d, 0x86, 0xdd, 0x19}, {0xe2, 0xd5, 0x49, 0x5e, 0x2a, 0x6e, 0x4e, 0xd9, 0x31, 0x26, 0x53, 0x13, 0x98, 0x5e, 0x2f, 0x23, 0xea, 0xa0, 0x30, 0xee, 0xef, 0x62, 0x2b, 0xdc, 0x93, 0x65, 0x90, 0xad, 0x9a, 0xf1, 0x74, 0x12, 0xf5, 0x24, 0x33, 0xcc, 0xc3, 0xda, 0x42, 0x54, 0xa6, 0x6c, 0x86, 0x99, 0xb9, 0xb5, 0xf7, 0x07, 0x90, 0xd8, 0x85, 0x7f, 0x69, 0xfb, 0x19, 0x2a, 0x2c, 0xc0, 0x11, 0x81, 0x64, 0x37, 0x38, 0x07}, {0xc7, 0xb3, 0xf5, 0xe4, 0x4b, 0x55, 0xcf, 0xd8, 0x2b, 0x72, 0xde, 0x62, 0xfc, 0x66, 0xea, 0x82, 0xee, 0x2e, 0xe5, 0x4f, 0x66, 0xba, 0x19, 0x63, 0x01, 0x0b, 0x2d, 0x89, 0xb4, 0xaa, 0x76, 0xb3, 0x7e, 0xc5, 0xbe, 0xdd, 0x57, 0x90, 0x5e, 0xff, 0x5b, 0x9a, 0x71, 0xe1, 0x47, 0xf9, 0xec, 0xe5, 0xf0, 0x19, 0x89, 0x17, 0x65, 0x3e, 0x56, 0x4a, 0x98, 0xb2, 0x3c, 0x3b, 0xf0, 0x14, 0x13, 0x1b}, {0xc0, 0x72, 0x26, 0x96, 0x6b, 0xf5, 0x50, 0xa1, 0x65, 0xcd, 0xfe, 0x92, 0xa5, 0x5a, 0xb3, 0x56, 0x27, 0x5b, 0x2f, 0x4a, 0x8f, 0x67, 0xaa, 0xf4, 0xa1, 0x6e, 0x3c, 0x66, 0xcc, 0xb7, 0x71, 0x70, 0xff, 0x70, 0x1f, 0x9e, 0x09, 0xae, 0x31, 0xcb, 0x2a, 0xd5, 0x8a, 0x38, 0xa9, 0xaf, 0xbc, 0x94, 0xa2, 0xa8, 0xe9, 0x77, 0x1c, 0xc3, 0xfa, 0xd1, 0x45, 0xd2, 0xe2, 0xff, 0x7d, 0xf2, 0x44, 0x00, 0xa0, 0xc3, 0xc1, 0xdd, 0xa0, 0x4c, 0xfb, 0xed, 0x1a, 0xbd, 0x0c, 0x05, 0x3b, 0xa9, 0xc8, 0x98, 0xb0, 0x7d, 0x6a, 0x77, 0xcb, 0x08, 0x70, 0x64, 0x31, 0x9d, 0x9c, 0x7b, 0x40, 0x9e, 0xbb, 0xf4}, {0xbc, 0x88, 0x9d, 0x36, 0xae, 0xbc, 0x92, 0x47, 0x63, 0x85, 0x41, 0xe3, 0x1e, 0x1c, 0x39, 0xf5, 0xd3, 0xc2, 0x0a, 0x7d, 0x18, 0x7a, 0x8f, 0xd3, 0x0c, 0x37, 0x50, 0x28, 0x35, 0x93, 0x77, 0x4b, 0xcb, 0xba, 0x35, 0x4e, 0x94, 0x48, 0xe4, 0x0c, 0xa7, 0x36, 0x4f, 0x74, 0x2b, 0xf9, 0xb5, 0xb5, 0xeb, 0x91, 0x50, 0x3c, 0x67, 0x9b, 0x4d, 0x25, 0xd4, 0x0e, 0x0d, 0xb9, 0x5b, 0x77, 0xf3, 0x0e, 0xa0, 0xc3, 0xc1, 0xdd, 0xa0, 0x4c, 0xfb, 0xed, 0x1a, 0xbd, 0x0c, 0x05, 0x3b, 0xa9, 0xc8, 0x98, 0xb0, 0x7d, 0x6a, 0x77, 0xcb, 0x08, 0x70, 0x64, 0x31, 0x9d, 0x9c, 0x7b, 0x40, 0x9e, 0xbb, 0xf4}}, - {{0x44, 0xdd, 0x62, 0x9e, 0x0f, 0xee, 0x20, 0x11, 0x37, 0xfc, 0xd0, 0x5c, 0xe4, 0xe1, 0x0a, 0xb8, 0xc2, 0xe0, 0x9c, 0x2c, 0x3e, 0x1b, 0x31, 0x1c, 0xdb, 0xa3, 0x84, 0x9a, 0xb7, 0x4e, 0x40, 0x74, 0x21, 0xfd, 0xfc, 0x65, 0xbd, 0x38, 0x8a, 0x55, 0x6f, 0x1e, 0xc3, 0x14, 0xfc, 0x66, 0x04, 0x7b, 0xc4, 0x61, 0xb0, 0xcb, 0xfa, 0xdd, 0x50, 0x45, 0x4b, 0x2e, 0xf0, 0x6d, 0x0f, 0x26, 0x6d, 0xbf}, {0xe6, 0xbc, 0x35, 0x73, 0xb3, 0x11, 0x38, 0xc6, 0x31, 0x82, 0x96, 0x80, 0x1d, 0xa9, 0xd9, 0x17, 0x85, 0x4e, 0xad, 0x0f, 0x5c, 0xb7, 0xe8, 0x78, 0x62, 0x2f, 0x3c, 0x10, 0x0e, 0xdc, 0xf2, 0x7e, 0xf5, 0x02, 0x6d, 0x1a, 0x50, 0xc2, 0x50, 0x7d, 0x0d, 0x14, 0x77, 0x77, 0xfc, 0xbe, 0x23, 0x02, 0x81, 0x0a, 0xdc, 0xa3, 0x16, 0xfd, 0xab, 0xb9, 0x7c, 0xb6, 0x7e, 0x8a, 0xde, 0x1f, 0x22, 0xeb}, {0xab, 0xf3, 0xea, 0x63, 0xc0, 0x25, 0xa2, 0xc7, 0x6a, 0xfe, 0x91, 0x4a, 0x0a, 0x91, 0xdd, 0x6d, 0x6f, 0x8c, 0xf9, 0xa8, 0x1c, 0x9f, 0xb5, 0xe5, 0xd2, 0xac, 0xe6, 0x51, 0x9a, 0xd3, 0x87, 0x17, 0x82, 0x12, 0x0a, 0x58, 0x99, 0x7f, 0x81, 0x2d, 0x8d, 0x27, 0x2d, 0x1b, 0xb0, 0x02, 0x7e, 0x0d, 0xd6, 0x18, 0x89, 0x5e, 0x0c, 0x2b, 0x57, 0xa6, 0x56, 0x35, 0xff, 0x71, 0x4e, 0xb0, 0x49, 0x38}, {0x36, 0xdf, 0x1d, 0x1c, 0xf6, 0xa7, 0x4d, 0x87, 0x7e, 0x2c, 0x3f, 0xb4, 0xda, 0xd7, 0x80, 0x71, 0x0b, 0xf3, 0x2a, 0x47, 0x20, 0xe6, 0x9a, 0x3d, 0x17, 0x9a, 0x97, 0xc9, 0x4e, 0x53, 0xa6, 0xe2, 0x23, 0xea, 0x94, 0x4d, 0xf9, 0xeb, 0x2c, 0x03, 0x2c, 0x88, 0xa2, 0xe6, 0xc5, 0x94, 0xa5, 0x6f, 0xc3, 0x98, 0xa9, 0x8b, 0xa7, 0x41, 0x7d, 0xd3, 0x82, 0x01, 0x13, 0xb6, 0x0f, 0x39, 0x1e, 0xd2}, {0x08, 0x28, 0xc3, 0x1c, 0xec, 0x21, 0x3a, 0xb4, 0x4c, 0xb1, 0xfa, 0xb9, 0x0c, 0xfe, 0xc2, 0x50, 0xc5, 0x99, 0x62, 0xa0, 0x11, 0x74, 0xcf, 0x05, 0x1e, 0x2b, 0xdf, 0x6d, 0x22, 0x8e, 0x6e, 0x55, 0x19, 0x21, 0x9c, 0xa1, 0x98, 0x56, 0x45, 0x90, 0x40, 0x3a, 0x8e, 0xad, 0x76, 0x4d, 0xd3, 0x95, 0x27, 0x67, 0x4e, 0x02, 0x16, 0xc3, 0xfe, 0x5a, 0x79, 0x4e, 0x2d, 0x6f, 0xd0, 0xe4, 0x4f, 0x62}, {0x40, 0x14, 0xe1, 0x88, 0x3d, 0xcc, 0x51, 0xcb, 0x98, 0x86, 0x06, 0x4d, 0xe4, 0x52, 0x71, 0xe2, 0x2e, 0x2b, 0x80, 0xfd, 0x81, 0x65, 0xaf, 0x93, 0x31, 0x87, 0xe0, 0xff, 0x31, 0xab, 0xff, 0x53, 0x0e, 0x2d, 0xb1, 0x47, 0xe6, 0x44, 0xb7, 0x29, 0xab, 0x0f, 0x51, 0x3a, 0x53, 0x84, 0x36, 0x58, 0x8c, 0x5f, 0x7b, 0x65, 0x6a, 0xb7, 0x6f, 0xdc, 0xad, 0xc1, 0xa3, 0xe4, 0x21, 0xfc, 0x22, 0x0e, 0xc1, 0x10, 0xd1, 0x7d, 0x9f, 0xd3, 0x1e, 0x33, 0xb4, 0xca, 0xb9, 0xff, 0xd8, 0x27, 0xb8, 0xca, 0xde, 0x49, 0x6f, 0xdc, 0xf0, 0xe8, 0x70, 0x36, 0xdb, 0x90, 0x00, 0x07, 0x9e, 0x77, 0x39, 0xfe}, {0xc9, 0x93, 0x4b, 0xe6, 0x47, 0x7e, 0x1d, 0x86, 0x15, 0x46, 0xe8, 0x27, 0xf5, 0x84, 0x67, 0x4e, 0x42, 0xe3, 0x2b, 0x8a, 0x4e, 0x90, 0x7b, 0x87, 0xcc, 0xdf, 0xaa, 0x04, 0x06, 0x05, 0xe6, 0x72, 0xff, 0x6f, 0x44, 0x1b, 0x08, 0xad, 0x79, 0x3e, 0xb7, 0xdd, 0xd7, 0x2c, 0x73, 0xf0, 0xf0, 0xc4, 0x6e, 0xb7, 0x37, 0xe1, 0x02, 0xf5, 0x42, 0xe7, 0xef, 0xa1, 0xdd, 0x50, 0x9a, 0xc5, 0x8d, 0x00, 0xc1, 0x10, 0xd1, 0x7d, 0x9f, 0xd3, 0x1e, 0x33, 0xb4, 0xca, 0xb9, 0xff, 0xd8, 0x27, 0xb8, 0xca, 0xde, 0x49, 0x6f, 0xdc, 0xf0, 0xe8, 0x70, 0x36, 0xdb, 0x90, 0x00, 0x07, 0x9e, 0x77, 0x39, 0xfe}}, - {{0x3e, 0x0c, 0x21, 0xc4, 0x3d, 0x64, 0x61, 0xc1, 0x9d, 0xa1, 0x83, 0x10, 0x74, 0x1d, 0x56, 0x12, 0xaf, 0x29, 0x5c, 0x6c, 0x12, 0x48, 0x0a, 0xc7, 0xe5, 0x12, 0xb6, 0x42, 0x6b, 0x54, 0xf4, 0x42, 0x0c, 0x43, 0x42, 0x2e, 0x78, 0xc2, 0xe7, 0x26, 0x09, 0x41, 0x4a, 0x2f, 0xa1, 0xb0, 0x1f, 0xcd, 0x63, 0x76, 0x1e, 0xa1, 0x6f, 0xf6, 0xe2, 0xc2, 0x08, 0x89, 0x0d, 0x28, 0xbf, 0x1b, 0x56, 0x5b}, {0x3e, 0x2e, 0xf2, 0xcc, 0x81, 0xca, 0xa7, 0x5d, 0x01, 0xd2, 0x82, 0xfd, 0x45, 0xee, 0xc0, 0xf5, 0x49, 0x3b, 0xe2, 0xa4, 0x2a, 0x4d, 0x5f, 0x40, 0x0d, 0xbc, 0xb9, 0x3d, 0x6e, 0xda, 0xe2, 0x86, 0xe1, 0x23, 0x8b, 0x5f, 0x0d, 0xa2, 0x35, 0x15, 0x1d, 0x22, 0x23, 0xa5, 0x69, 0x56, 0x34, 0x78, 0xb3, 0xb3, 0x55, 0xef, 0x63, 0x8a, 0x17, 0x63, 0xda, 0xf0, 0x64, 0x99, 0x8a, 0x8a, 0xba, 0xd6}, {0x68, 0x79, 0x36, 0xa7, 0x6b, 0xe3, 0x76, 0x1c, 0xe3, 0x38, 0x0b, 0xa3, 0x91, 0xb6, 0xb0, 0x82, 0x37, 0xfa, 0x52, 0x74, 0xf1, 0xb5, 0xd5, 0xd9, 0x07, 0x06, 0x9e, 0xda, 0x87, 0x6b, 0x0f, 0x24, 0x4f, 0xbe, 0xc9, 0xff, 0x03, 0x41, 0xaf, 0x77, 0x68, 0xed, 0xe7, 0x71, 0xba, 0x2d, 0xde, 0x27, 0xa1, 0xbf, 0xa8, 0xa7, 0x30, 0x7c, 0xcb, 0x79, 0x72, 0x89, 0x1a, 0xdc, 0xc1, 0xe4, 0xb2, 0x9d}, {0x94, 0xa3, 0x11, 0xf4, 0x44, 0x80, 0xd0, 0xa3, 0x47, 0x93, 0x36, 0xe2, 0xbd, 0x04, 0xe4, 0x74, 0x3d, 0x00, 0x60, 0xad, 0xd0, 0x2d, 0x86, 0x66, 0xa1, 0x72, 0x1a, 0xb9, 0x1c, 0x14, 0xa2, 0x9b, 0x4b, 0x04, 0x7d, 0x5b, 0xcd, 0xf8, 0x01, 0x33, 0xde, 0x34, 0x10, 0x29, 0xc4, 0x72, 0x56, 0xff, 0x11, 0xcd, 0xd8, 0x61, 0x2c, 0xb6, 0xb7, 0xf4, 0x24, 0x8b, 0x44, 0xb4, 0xe7, 0x34, 0x50, 0xb8}, {0x72, 0xf6, 0xd4, 0xa3, 0x24, 0xf9, 0xef, 0xf4, 0x55, 0x8d, 0x3c, 0x07, 0xca, 0x10, 0xdd, 0x54, 0x87, 0x13, 0x32, 0x78, 0x5c, 0x64, 0x10, 0x08, 0x62, 0x7e, 0xf4, 0x34, 0x0f, 0x1c, 0xcd, 0xcc, 0x3b, 0x42, 0xfe, 0x60, 0x41, 0x70, 0x2c, 0x6b, 0xd4, 0x6c, 0xf7, 0xb8, 0x24, 0xf6, 0xd7, 0x07, 0xb3, 0x46, 0xb0, 0x7d, 0x14, 0x24, 0x9b, 0x72, 0x79, 0xf4, 0x23, 0x2a, 0xec, 0x02, 0xe7, 0x69}, {0xe5, 0xbe, 0x84, 0xc3, 0x92, 0x47, 0x15, 0xd3, 0xac, 0x06, 0x44, 0x72, 0x41, 0xeb, 0xb6, 0x5a, 0x17, 0x06, 0x90, 0xd9, 0x55, 0x3d, 0xe4, 0x87, 0x7d, 0x5a, 0x11, 0x9f, 0x02, 0x6d, 0xd3, 0x4e, 0x71, 0xd1, 0x5e, 0x16, 0x9f, 0xb2, 0xc0, 0x7f, 0xcb, 0x78, 0x8b, 0x89, 0x11, 0xae, 0x43, 0xe8, 0x85, 0xb7, 0xf9, 0xc8, 0x48, 0x5a, 0xb2, 0x96, 0xaf, 0x8f, 0xab, 0x71, 0x84, 0x9d, 0x40, 0x09, 0x30, 0xd4, 0x32, 0x6e, 0xa2, 0x77, 0x97, 0x71, 0x37, 0xce, 0x22, 0x6b, 0xca, 0xc9, 0x79, 0xef, 0xc0, 0xb2, 0xb4, 0x3d, 0x30, 0xbf, 0x77, 0xe9, 0xc3, 0x8d, 0xec, 0x15, 0x04, 0x08, 0xfa, 0x15}, {0x4b, 0xf3, 0x7f, 0xb2, 0x78, 0x75, 0x45, 0xd4, 0xce, 0x5e, 0x3d, 0xaf, 0x92, 0x63, 0x3d, 0x90, 0xc0, 0xa7, 0x23, 0x62, 0x7f, 0x37, 0x58, 0x8d, 0x12, 0xe0, 0xb8, 0x6c, 0x46, 0x38, 0xaa, 0xf7, 0xe1, 0x03, 0x9e, 0x1f, 0x31, 0xf9, 0x5a, 0xa4, 0x59, 0x0d, 0xec, 0xc5, 0x1f, 0x17, 0x88, 0x25, 0xcc, 0xed, 0x69, 0x2b, 0x91, 0x73, 0x6a, 0x3f, 0xcb, 0xe5, 0x9c, 0x1e, 0x26, 0x3e, 0xec, 0x0b, 0x30, 0xd4, 0x32, 0x6e, 0xa2, 0x77, 0x97, 0x71, 0x37, 0xce, 0x22, 0x6b, 0xca, 0xc9, 0x79, 0xef, 0xc0, 0xb2, 0xb4, 0x3d, 0x30, 0xbf, 0x77, 0xe9, 0xc3, 0x8d, 0xec, 0x15, 0x04, 0x08, 0xfa, 0x15}}, - {{0xc5, 0x1d, 0xcd, 0x70, 0xb2, 0x9e, 0x53, 0x29, 0x05, 0x78, 0x83, 0x5d, 0x56, 0x30, 0x89, 0xee, 0x02, 0xd7, 0xac, 0x57, 0x0a, 0xd2, 0xa0, 0x9c, 0x96, 0x0c, 0xbf, 0xf2, 0x30, 0xbf, 0x1a, 0x2b, 0xee, 0x0e, 0x9f, 0x1e, 0x1c, 0x65, 0x7d, 0xb5, 0x48, 0xad, 0x6f, 0x51, 0xa0, 0x91, 0x61, 0xe4, 0xe6, 0x83, 0x9f, 0x58, 0x7c, 0x76, 0x2b, 0x52, 0x94, 0x87, 0x3c, 0x8d, 0x36, 0x4c, 0x37, 0x3c}, {0x59, 0x3b, 0x0d, 0x38, 0xab, 0x93, 0xca, 0xfb, 0x67, 0x44, 0x30, 0x96, 0xec, 0xbd, 0x00, 0x1d, 0x93, 0xd0, 0xb3, 0x3d, 0x3c, 0xd4, 0x4e, 0x3d, 0xd8, 0x29, 0x93, 0xb2, 0xb3, 0x77, 0xfc, 0x57, 0x31, 0x20, 0xe3, 0x90, 0x0d, 0xf4, 0x91, 0x2f, 0x8b, 0x43, 0xce, 0xfe, 0x99, 0x03, 0x03, 0xa2, 0x90, 0x8d, 0xcf, 0xa8, 0xc0, 0x21, 0x00, 0xca, 0xcc, 0xcb, 0x4b, 0x2f, 0xa5, 0x39, 0xa8, 0x0b}, {0xca, 0xf6, 0xf9, 0xbb, 0x53, 0xcb, 0x97, 0x76, 0xb6, 0x9c, 0x2c, 0x18, 0x21, 0x43, 0x13, 0x48, 0x13, 0xc9, 0x0e, 0xeb, 0x40, 0xea, 0xce, 0x1f, 0x3a, 0xe9, 0xd2, 0x9e, 0x29, 0xdb, 0xe2, 0x79, 0xe2, 0x1a, 0x9f, 0x84, 0x9d, 0xe4, 0x55, 0x82, 0x17, 0xeb, 0x87, 0xf6, 0xc3, 0xef, 0xcd, 0x54, 0x14, 0xee, 0xc8, 0x5b, 0xd7, 0x67, 0x05, 0xe2, 0x34, 0xa2, 0x7e, 0x81, 0x83, 0x21, 0x7a, 0x02}, {0xc5, 0x03, 0xd9, 0x75, 0xdf, 0x17, 0x15, 0xe3, 0x5b, 0x7b, 0x4f, 0x66, 0x9c, 0x15, 0x4e, 0x01, 0xdf, 0x3d, 0x16, 0xb6, 0x52, 0xcc, 0xcf, 0x28, 0x40, 0xdb, 0x20, 0xee, 0x8b, 0x69, 0xb1, 0x2b, 0xc0, 0x6e, 0xe4, 0xd2, 0xf5, 0xd1, 0x49, 0x3f, 0xf3, 0x0a, 0x12, 0xcd, 0x13, 0xbd, 0x9d, 0x3d, 0x5b, 0x28, 0x5c, 0xb0, 0x0d, 0x0e, 0xb6, 0xed, 0xec, 0x65, 0xeb, 0x25, 0x28, 0x2e, 0x65, 0x2f}, {0xed, 0xa7, 0x05, 0xc1, 0xa6, 0x81, 0xf2, 0x7a, 0x69, 0x68, 0x17, 0x8e, 0xf7, 0xc9, 0x14, 0x80, 0x9f, 0x81, 0xfe, 0x16, 0xfd, 0x81, 0x93, 0xb4, 0x0b, 0x05, 0x5b, 0x4e, 0xef, 0x6e, 0x7a, 0x67, 0x9d, 0x99, 0x4c, 0x17, 0xcd, 0x1c, 0x16, 0xfd, 0x31, 0x35, 0xd5, 0x3e, 0xa3, 0x00, 0xbf, 0xbe, 0xda, 0xd6, 0xe2, 0x37, 0x9b, 0x13, 0x1b, 0xca, 0x29, 0x90, 0x4b, 0xf2, 0x09, 0x57, 0x2f, 0xe9}, {0xd7, 0xba, 0x23, 0xd3, 0xa0, 0x6e, 0x14, 0x6a, 0xf0, 0x77, 0xb7, 0xe6, 0xe3, 0xc9, 0x3b, 0x38, 0xbb, 0xe7, 0xbe, 0x54, 0x75, 0xf8, 0xb7, 0x42, 0x29, 0xe2, 0x83, 0xde, 0x20, 0x22, 0x41, 0xcf, 0x5f, 0x6f, 0x80, 0x60, 0xf3, 0x44, 0x04, 0x21, 0xd5, 0x03, 0x68, 0x42, 0xde, 0x81, 0xea, 0xe8, 0x7e, 0x5b, 0x80, 0x0f, 0x1b, 0x2d, 0x06, 0xc7, 0xce, 0xe9, 0x46, 0xc7, 0xf7, 0xb3, 0xa2, 0x02, 0x21, 0xb5, 0x4d, 0xc2, 0x36, 0xea, 0xe6, 0x7b, 0xb3, 0x61, 0xe6, 0x18, 0x40, 0x5b, 0xce, 0x5b, 0xc2, 0xee, 0xa5, 0xde, 0xe9, 0xe6, 0xe0, 0xa8, 0x58, 0x58, 0x03, 0x34, 0x26, 0x27, 0x65, 0x2a}, {0xfa, 0x43, 0xa6, 0xc4, 0x32, 0xa1, 0x2f, 0xb6, 0x37, 0x05, 0xf4, 0xa4, 0xa7, 0x36, 0xdd, 0x1c, 0x45, 0x10, 0x95, 0x83, 0x67, 0x89, 0x79, 0x18, 0x34, 0xad, 0xe7, 0x57, 0x7f, 0x0d, 0x48, 0x9b, 0x14, 0xdf, 0x5f, 0xc8, 0xd7, 0x0f, 0x78, 0x47, 0x88, 0x20, 0xff, 0x7f, 0xb1, 0x21, 0x27, 0x14, 0x58, 0x32, 0x12, 0xfb, 0x97, 0xe0, 0x81, 0x0e, 0x92, 0xf4, 0x5c, 0x0e, 0x44, 0x48, 0x4e, 0x01, 0x21, 0xb5, 0x4d, 0xc2, 0x36, 0xea, 0xe6, 0x7b, 0xb3, 0x61, 0xe6, 0x18, 0x40, 0x5b, 0xce, 0x5b, 0xc2, 0xee, 0xa5, 0xde, 0xe9, 0xe6, 0xe0, 0xa8, 0x58, 0x58, 0x03, 0x34, 0x26, 0x27, 0x65, 0x2a}}, - {{0x1e, 0x89, 0x12, 0xe8, 0xab, 0xca, 0xeb, 0x96, 0x78, 0x43, 0x89, 0x79, 0x26, 0x61, 0x86, 0x2e, 0x37, 0xd7, 0x94, 0xb5, 0xb9, 0xf7, 0xc9, 0xe7, 0x04, 0x6c, 0x96, 0x1c, 0x54, 0x0d, 0xb0, 0x6c, 0xd3, 0x68, 0x9b, 0x53, 0xa7, 0x56, 0x34, 0x1b, 0x65, 0xff, 0xf9, 0xee, 0xf1, 0xc6, 0xfd, 0x7e, 0xa8, 0x42, 0x59, 0x60, 0x06, 0x5f, 0xc2, 0x89, 0x8b, 0xfc, 0xf8, 0x6c, 0x9a, 0x0d, 0xb1, 0x36}, {0x52, 0x3d, 0x83, 0x25, 0x0f, 0x57, 0x81, 0x76, 0x7b, 0x21, 0xf7, 0x96, 0xd6, 0x1f, 0xfe, 0xd7, 0x7c, 0xc1, 0x32, 0xb5, 0xbc, 0x05, 0x46, 0xdb, 0x6f, 0x25, 0xd8, 0x7a, 0x68, 0xe2, 0x01, 0x81, 0xf8, 0x9a, 0xc5, 0x29, 0x78, 0x1c, 0x01, 0xc5, 0x4d, 0x61, 0x4e, 0x75, 0xdf, 0x9f, 0xc3, 0x22, 0x96, 0x7c, 0xf9, 0xa7, 0xed, 0x41, 0x6f, 0x64, 0xfd, 0xd4, 0x61, 0x58, 0x0d, 0x49, 0xc9, 0xa4}, {0x4a, 0xf7, 0xda, 0xef, 0xe0, 0x3b, 0x33, 0x19, 0x79, 0x02, 0x7a, 0xbb, 0xd3, 0x53, 0xf4, 0x8c, 0x8a, 0x16, 0xfb, 0xbd, 0x35, 0xd9, 0x70, 0xb2, 0x0a, 0x06, 0x05, 0x14, 0xd0, 0x9e, 0xf6, 0x13, 0x44, 0xbb, 0xb7, 0x93, 0x86, 0x1b, 0x3c, 0xb0, 0x54, 0xa7, 0x48, 0xc2, 0xa7, 0x10, 0xda, 0x65, 0xb2, 0xdb, 0x0f, 0x85, 0x23, 0x57, 0x77, 0x44, 0x23, 0x20, 0x6d, 0x2e, 0xde, 0x20, 0x01, 0xed}, {0x9c, 0xb8, 0x68, 0xeb, 0xbb, 0x8b, 0xaf, 0x81, 0x9c, 0x2f, 0x90, 0x4c, 0xc2, 0x62, 0x17, 0xfc, 0xf2, 0xa5, 0xab, 0x4c, 0x2e, 0x69, 0xcb, 0x82, 0x5f, 0x4c, 0x3c, 0x82, 0xcd, 0x6a, 0xcb, 0x15, 0xa2, 0xfc, 0x50, 0x54, 0x5e, 0x2e, 0x83, 0x52, 0x48, 0x29, 0x51, 0xcc, 0x50, 0xaa, 0x27, 0xa3, 0xf3, 0x71, 0xdb, 0x2c, 0x1c, 0xa9, 0x8a, 0xa5, 0x95, 0xab, 0x3e, 0x6f, 0xcd, 0xba, 0x22, 0x7c}, {0xf7, 0x5d, 0xb5, 0x20, 0x65, 0xfe, 0xa9, 0xe7, 0x1f, 0x8e, 0xd6, 0xc0, 0xf2, 0x3f, 0x1b, 0x8c, 0x7a, 0x02, 0x54, 0xd8, 0xa7, 0x0e, 0x6f, 0x68, 0x94, 0x81, 0xff, 0x30, 0x0e, 0x6d, 0x1a, 0x96, 0x1b, 0x86, 0x07, 0xaa, 0xbf, 0x37, 0xc5, 0x5e, 0x26, 0xa2, 0xdf, 0x0b, 0xd0, 0x7f, 0x94, 0x35, 0x30, 0xa4, 0x9e, 0x47, 0xaf, 0xad, 0x9c, 0xc9, 0x02, 0x21, 0x55, 0x94, 0x04, 0x13, 0xff, 0x64}, {0x9c, 0x8d, 0x18, 0x63, 0x83, 0xad, 0x01, 0xcc, 0xbb, 0xe6, 0x00, 0xda, 0x15, 0xce, 0xc6, 0x6e, 0x7a, 0x37, 0x6a, 0x81, 0x44, 0xb3, 0xfc, 0xb7, 0xcd, 0x05, 0xee, 0x4a, 0x6f, 0x29, 0xe4, 0x79, 0x63, 0x52, 0x7e, 0x14, 0xc9, 0x14, 0x77, 0xa8, 0x19, 0x94, 0x03, 0xc6, 0x51, 0x57, 0xf1, 0xcc, 0x11, 0x29, 0xde, 0x86, 0x08, 0xfe, 0x41, 0x02, 0x71, 0xb7, 0xbf, 0xd7, 0xe7, 0x83, 0x3e, 0x0c, 0x9a, 0x59, 0x7e, 0xe8, 0x61, 0x36, 0x56, 0x9a, 0xbf, 0x64, 0xfd, 0xf3, 0xb7, 0xb9, 0x2f, 0x9e, 0x56, 0x1f, 0x57, 0x45, 0x2e, 0x19, 0x0f, 0x6f, 0x70, 0x01, 0xc2, 0x48, 0x05, 0x23, 0x9b, 0x2f}, {0xb5, 0x4e, 0xe7, 0xcc, 0x7b, 0x66, 0x7a, 0xf8, 0xec, 0xcd, 0x1b, 0x0c, 0x0f, 0xec, 0x04, 0x27, 0xa0, 0x61, 0xfd, 0x12, 0x2d, 0xab, 0xc9, 0xc5, 0x8e, 0xee, 0x36, 0xc2, 0xef, 0x67, 0xd5, 0x87, 0x95, 0x6c, 0x12, 0xb7, 0x12, 0x81, 0x55, 0xe0, 0x7b, 0xdb, 0x8f, 0x67, 0xea, 0x04, 0x55, 0x91, 0x9b, 0x50, 0x65, 0x05, 0xc1, 0xf1, 0x0b, 0x04, 0x91, 0x66, 0x3c, 0x32, 0x53, 0x72, 0x01, 0x04, 0x9a, 0x59, 0x7e, 0xe8, 0x61, 0x36, 0x56, 0x9a, 0xbf, 0x64, 0xfd, 0xf3, 0xb7, 0xb9, 0x2f, 0x9e, 0x56, 0x1f, 0x57, 0x45, 0x2e, 0x19, 0x0f, 0x6f, 0x70, 0x01, 0xc2, 0x48, 0x05, 0x23, 0x9b, 0x2f}}, - {{0xc8, 0x37, 0x10, 0xdc, 0xdb, 0xfc, 0x51, 0x91, 0xae, 0x37, 0xa4, 0xe0, 0xcf, 0xbb, 0xdd, 0x92, 0x93, 0x5f, 0x6b, 0xd6, 0x81, 0xbf, 0x9b, 0x24, 0x5e, 0x0d, 0xf1, 0xe4, 0x04, 0x89, 0xd1, 0x1b, 0xb2, 0x68, 0x56, 0x3a, 0xdc, 0x59, 0xd0, 0x8a, 0x93, 0x37, 0x5d, 0xa5, 0x40, 0x5e, 0xfe, 0xc9, 0x41, 0x0b, 0x8a, 0x50, 0xd2, 0xa0, 0x94, 0x86, 0xf7, 0x46, 0x3b, 0x7e, 0x1d, 0xea, 0x2b, 0xa8}, {0x1b, 0xe2, 0xe6, 0x48, 0x86, 0xa8, 0x65, 0xfd, 0x2b, 0xae, 0xc7, 0x7d, 0x41, 0xee, 0xb2, 0x80, 0x33, 0x1c, 0x0a, 0xdc, 0x42, 0xea, 0x99, 0xd0, 0x1f, 0x6d, 0xc8, 0x80, 0x51, 0x70, 0xd4, 0x19, 0xae, 0xfc, 0x66, 0x16, 0xa2, 0x53, 0x27, 0x19, 0x7a, 0xf2, 0x9a, 0x25, 0x0c, 0x39, 0x8c, 0xbf, 0xe7, 0xa3, 0x7a, 0xd6, 0xa3, 0x43, 0x62, 0xd2, 0x4a, 0xc2, 0xf1, 0x96, 0x7e, 0xe3, 0x83, 0x13}, {0xf5, 0xb1, 0x2a, 0xc5, 0x4d, 0xcc, 0xdf, 0x56, 0xde, 0x92, 0x96, 0x46, 0x03, 0x11, 0xfc, 0xa0, 0xbc, 0xa2, 0x22, 0xf7, 0x25, 0x74, 0x2a, 0x1f, 0x27, 0x34, 0x18, 0xe8, 0x06, 0xa4, 0x77, 0x26, 0x1a, 0x51, 0x5e, 0xfb, 0x77, 0xbc, 0x55, 0xb1, 0xf8, 0xa5, 0x19, 0x23, 0x00, 0x97, 0xf7, 0xbb, 0xe4, 0xcd, 0x41, 0x9e, 0xd9, 0x5e, 0x0c, 0x6b, 0x1b, 0x8a, 0xba, 0x52, 0x93, 0xbe, 0x2c, 0xf3}, {0xb3, 0x02, 0xeb, 0x44, 0x3c, 0x05, 0xae, 0x9c, 0x94, 0xa9, 0x1f, 0x72, 0x41, 0xbc, 0x81, 0x66, 0x5f, 0x50, 0xc0, 0x57, 0xb4, 0x44, 0xf0, 0xe1, 0x2a, 0xa9, 0x88, 0x69, 0xa6, 0x1c, 0x05, 0x85, 0xda, 0xc7, 0xb2, 0xe1, 0x8c, 0x2f, 0x7c, 0x49, 0x37, 0xa2, 0xf2, 0x56, 0xab, 0x12, 0x9f, 0x12, 0x4b, 0x1b, 0x73, 0x75, 0x3f, 0x30, 0x0f, 0x40, 0xf1, 0xf9, 0x1d, 0xa7, 0x2c, 0x98, 0x8c, 0x91}, {0xcb, 0xd3, 0x39, 0x60, 0x56, 0xe3, 0xbd, 0x65, 0x86, 0x1a, 0x58, 0x40, 0xc0, 0xa4, 0xc4, 0x8b, 0xe5, 0xf7, 0x49, 0x0a, 0xf2, 0x09, 0x51, 0x32, 0x6e, 0x06, 0x5a, 0x27, 0x19, 0x78, 0x2e, 0x3a, 0x04, 0xf9, 0x34, 0x80, 0x49, 0x39, 0x93, 0xcd, 0x89, 0x67, 0x7b, 0xc0, 0x8d, 0x9d, 0x8d, 0x4c, 0x83, 0x20, 0x80, 0xfc, 0x00, 0xf2, 0x8a, 0x8f, 0xa4, 0x4d, 0x8e, 0x8f, 0x58, 0x51, 0x5b, 0x71}, {0x71, 0x3f, 0x90, 0x41, 0xb8, 0x74, 0xbc, 0x7a, 0x85, 0xf5, 0xab, 0xca, 0x7e, 0xf2, 0x70, 0x41, 0xbc, 0x36, 0xb5, 0xc3, 0x4e, 0xf1, 0x2b, 0x17, 0x35, 0x40, 0xdb, 0x3c, 0xdb, 0xd2, 0xec, 0x0b, 0x99, 0xc1, 0x43, 0x17, 0xad, 0x38, 0x45, 0x2d, 0x07, 0x31, 0xd7, 0xb6, 0x95, 0x1c, 0x89, 0x25, 0xe4, 0x89, 0x97, 0xd3, 0xcf, 0x11, 0x2f, 0x63, 0x31, 0x51, 0xa2, 0x18, 0xfc, 0x12, 0x04, 0x0a, 0xb0, 0x33, 0xce, 0x0b, 0x57, 0xc0, 0x8c, 0x58, 0x25, 0xf8, 0x9b, 0x50, 0x22, 0x1c, 0x5c, 0x7b, 0x02, 0xc7, 0xed, 0xfc, 0x98, 0x8b, 0xbd, 0xd2, 0x4e, 0xfc, 0x78, 0x91, 0x7f, 0x4c, 0x99, 0x24}, {0xfc, 0x46, 0xe4, 0x85, 0x0c, 0x52, 0x14, 0xf8, 0x8a, 0xa4, 0x97, 0x17, 0x10, 0xb2, 0x93, 0xef, 0xa0, 0x66, 0x3c, 0xfd, 0x61, 0x42, 0x24, 0x30, 0x70, 0x4b, 0xfd, 0x0b, 0x86, 0xc8, 0x97, 0xd7, 0x04, 0xc2, 0xa6, 0x61, 0x41, 0xaf, 0xcc, 0x1d, 0x52, 0xc9, 0xf3, 0xca, 0xe1, 0x90, 0x7c, 0xbd, 0xce, 0xaf, 0x30, 0xc4, 0xb4, 0x7d, 0x81, 0x7e, 0xbd, 0xe2, 0x09, 0x70, 0x1e, 0x6b, 0xb9, 0x03, 0xb0, 0x33, 0xce, 0x0b, 0x57, 0xc0, 0x8c, 0x58, 0x25, 0xf8, 0x9b, 0x50, 0x22, 0x1c, 0x5c, 0x7b, 0x02, 0xc7, 0xed, 0xfc, 0x98, 0x8b, 0xbd, 0xd2, 0x4e, 0xfc, 0x78, 0x91, 0x7f, 0x4c, 0x99, 0x24}}, - {{0x5f, 0x01, 0x6d, 0xec, 0x82, 0x02, 0x96, 0x47, 0x74, 0xd9, 0x73, 0x2e, 0x2e, 0x17, 0x00, 0xb6, 0xe0, 0xa4, 0x13, 0x17, 0xae, 0x7f, 0x85, 0xcb, 0xff, 0xe7, 0x96, 0x99, 0xdb, 0x9f, 0xad, 0x21, 0x60, 0xd9, 0x12, 0xdc, 0x41, 0x01, 0x33, 0x66, 0x4c, 0x24, 0x8b, 0x25, 0x17, 0xd7, 0x22, 0x14, 0x12, 0x4d, 0xad, 0x82, 0x9a, 0x85, 0x69, 0x5e, 0x35, 0x10, 0xe0, 0xd7, 0x1a, 0x82, 0x88, 0x14}, {0xab, 0x5f, 0x2c, 0x7d, 0xa2, 0xe5, 0x67, 0x5f, 0xe4, 0x92, 0x03, 0x93, 0xd7, 0x13, 0xa1, 0xfa, 0x4a, 0xb7, 0x18, 0x4a, 0x8e, 0x8c, 0x78, 0x9a, 0x0c, 0x60, 0x02, 0xe8, 0x2d, 0x50, 0x05, 0x0f, 0x92, 0xee, 0x9f, 0x81, 0xde, 0x6b, 0x20, 0xe4, 0x9b, 0x17, 0x2e, 0x99, 0x0f, 0x01, 0x31, 0xa7, 0xc5, 0xc4, 0x53, 0x70, 0xda, 0x03, 0xc6, 0xf7, 0x22, 0x87, 0x98, 0x87, 0x19, 0x36, 0xa6, 0x49}, {0x93, 0xab, 0x22, 0xc4, 0x39, 0x6c, 0x97, 0x80, 0xd2, 0xe2, 0x36, 0xfa, 0x31, 0x74, 0x67, 0xcc, 0x50, 0x1b, 0x95, 0xbe, 0x77, 0xe0, 0xd1, 0x00, 0x74, 0x04, 0xe1, 0x4d, 0xca, 0x44, 0x35, 0x72, 0x74, 0x69, 0x82, 0x23, 0x56, 0x9b, 0xcc, 0x34, 0x5a, 0xcb, 0xa2, 0xa3, 0x31, 0x12, 0x4a, 0x84, 0x4c, 0xe9, 0x37, 0x3a, 0x58, 0xf8, 0x79, 0x65, 0x4a, 0x66, 0x79, 0x82, 0xf4, 0x5d, 0x75, 0xc3}, {0x2d, 0x5d, 0xac, 0x4f, 0xb5, 0x00, 0x68, 0x3b, 0x5f, 0x2e, 0xdd, 0xcb, 0x14, 0x4a, 0x7f, 0xad, 0x12, 0x45, 0x91, 0xd1, 0x84, 0xd8, 0x14, 0xff, 0xcb, 0x64, 0x43, 0x6d, 0x65, 0xe7, 0x19, 0x68, 0x2b, 0x5e, 0x53, 0x05, 0x74, 0x66, 0xed, 0xac, 0x2f, 0x5a, 0x8f, 0x70, 0x96, 0xab, 0x29, 0xf3, 0x9a, 0x59, 0xa2, 0xe2, 0xef, 0xd3, 0xc9, 0xd7, 0x53, 0xf8, 0xf5, 0xa3, 0xd6, 0xf4, 0x34, 0xf8}, {0x1d, 0x14, 0xf3, 0xfd, 0xb0, 0x66, 0x20, 0xff, 0xfc, 0x79, 0x47, 0xc7, 0x4c, 0xe9, 0x45, 0x67, 0xf5, 0x97, 0x14, 0xea, 0x7c, 0x63, 0xc5, 0x3f, 0x0b, 0x46, 0xe0, 0x88, 0xd6, 0x9b, 0x67, 0x71, 0xba, 0xa6, 0x15, 0x28, 0x94, 0x54, 0x83, 0x68, 0x00, 0x3a, 0x33, 0xa6, 0x1a, 0x05, 0x6a, 0x68, 0x72, 0x98, 0x48, 0x71, 0xea, 0x5b, 0x47, 0xf5, 0x80, 0x46, 0xa9, 0x57, 0x84, 0xec, 0xad, 0xfc}, {0xa3, 0x1d, 0x87, 0xd3, 0x28, 0x62, 0xc6, 0xf7, 0xdb, 0xfb, 0xfa, 0xfc, 0xf3, 0x27, 0x5c, 0x31, 0xd3, 0x32, 0x26, 0x0e, 0x0f, 0x41, 0x49, 0xec, 0x05, 0x16, 0xf7, 0xa5, 0x63, 0xb3, 0xbc, 0xe5, 0x0d, 0x1e, 0x6f, 0x97, 0x4f, 0x68, 0x40, 0xc0, 0xd4, 0x6c, 0x4f, 0x9e, 0x25, 0xd0, 0xab, 0x8d, 0x2a, 0xb9, 0x3e, 0x06, 0x4d, 0x9d, 0x3d, 0x2d, 0x79, 0x8d, 0x93, 0xdc, 0xfc, 0x6f, 0x0b, 0x04, 0x48, 0x7c, 0x19, 0x5c, 0xa9, 0xc8, 0x44, 0xe5, 0xf6, 0x4f, 0x51, 0xd8, 0x72, 0x63, 0x41, 0xda, 0x62, 0xac, 0x78, 0x73, 0xb3, 0x3e, 0xc8, 0xb2, 0xf1, 0x3f, 0x89, 0xf2, 0x0e, 0x95, 0xdf, 0xed}, {0xfd, 0x69, 0xb1, 0x9a, 0xdb, 0xae, 0x95, 0x87, 0xe2, 0xc6, 0x8a, 0x97, 0x0c, 0xee, 0xc4, 0x22, 0x60, 0x4e, 0x96, 0xa9, 0x72, 0xb9, 0x6f, 0x86, 0x97, 0xa8, 0xdf, 0x83, 0xc5, 0x18, 0x18, 0x6e, 0xc9, 0x43, 0x30, 0x7e, 0x5b, 0xcf, 0x37, 0x0f, 0xc1, 0xd7, 0xe5, 0xab, 0xb1, 0x31, 0xe0, 0x97, 0xc7, 0x53, 0xb7, 0xfd, 0xd7, 0xdf, 0x00, 0x43, 0x0e, 0x41, 0x62, 0x80, 0x0b, 0xe3, 0xe0, 0x06, 0x48, 0x7c, 0x19, 0x5c, 0xa9, 0xc8, 0x44, 0xe5, 0xf6, 0x4f, 0x51, 0xd8, 0x72, 0x63, 0x41, 0xda, 0x62, 0xac, 0x78, 0x73, 0xb3, 0x3e, 0xc8, 0xb2, 0xf1, 0x3f, 0x89, 0xf2, 0x0e, 0x95, 0xdf, 0xed}}, - {{0x98, 0x29, 0xf7, 0x57, 0xfd, 0xbd, 0x44, 0x3f, 0xd9, 0x90, 0x98, 0x19, 0x97, 0xf2, 0x60, 0x27, 0xfd, 0x08, 0xfc, 0x8a, 0xc6, 0xaf, 0x87, 0x22, 0x7f, 0x74, 0x4a, 0x80, 0xaf, 0x72, 0x00, 0x01, 0x70, 0x9b, 0x47, 0x2a, 0xd2, 0x8e, 0x41, 0x0a, 0xea, 0x6a, 0xdf, 0xb7, 0x61, 0x54, 0x89, 0x5e, 0x01, 0x9f, 0x76, 0x64, 0x29, 0xee, 0x8d, 0x85, 0x20, 0xff, 0x30, 0x58, 0xc2, 0xa3, 0x2a, 0x56}, {0xea, 0x69, 0x8e, 0x6b, 0x8e, 0xdd, 0x55, 0x22, 0x45, 0x61, 0xd4, 0x92, 0x66, 0x8e, 0x96, 0xaf, 0x7e, 0x40, 0x28, 0x72, 0xc4, 0x46, 0xe7, 0x88, 0xd4, 0x6c, 0x74, 0xb7, 0x48, 0x7f, 0xe8, 0xe1, 0x5e, 0xa5, 0x85, 0x62, 0x8f, 0xd6, 0xfc, 0x27, 0x0a, 0xb2, 0x4b, 0x38, 0x94, 0x59, 0x52, 0x0d, 0x6a, 0x4d, 0xe5, 0x61, 0xce, 0x0d, 0x44, 0x03, 0xa6, 0x2a, 0xc2, 0xd4, 0xd4, 0xe2, 0x71, 0xe3}, {0x40, 0xf0, 0x82, 0xf0, 0x8d, 0xaa, 0xad, 0xa9, 0x9f, 0x9b, 0x85, 0x02, 0xcf, 0x57, 0x15, 0x41, 0x13, 0x59, 0xf2, 0xba, 0xdd, 0xbf, 0x93, 0xe5, 0x40, 0x2e, 0xaf, 0xdd, 0x43, 0x52, 0xc8, 0x7f, 0x40, 0xad, 0x91, 0x5b, 0x58, 0xd1, 0xa1, 0xe8, 0x6f, 0x77, 0xc3, 0x41, 0x35, 0x5e, 0xf7, 0x03, 0xba, 0xe4, 0xed, 0x2c, 0x28, 0x59, 0xd6, 0x48, 0xfe, 0x50, 0xcc, 0xf9, 0x80, 0xd1, 0x49, 0xd1}, {0xd7, 0xa5, 0xd9, 0x13, 0xdf, 0x7d, 0xf6, 0xc6, 0x25, 0x0f, 0x52, 0xc2, 0x57, 0x61, 0x20, 0xf2, 0xf0, 0xdb, 0x47, 0x49, 0x56, 0xaf, 0x89, 0x11, 0xa7, 0x8d, 0x09, 0x3a, 0xfe, 0x45, 0x43, 0xef, 0x9f, 0x0c, 0x42, 0xaf, 0xa8, 0xcc, 0x60, 0x48, 0xc0, 0x1c, 0x7c, 0xbe, 0x01, 0xe2, 0x88, 0xcc, 0x6c, 0x3e, 0x97, 0x91, 0xf3, 0xd9, 0xb2, 0xb2, 0x09, 0x7e, 0x35, 0xb1, 0x78, 0xb4, 0x03, 0xf6}, {0x08, 0xc4, 0x1a, 0x3a, 0xc3, 0xe3, 0x26, 0xbd, 0x8d, 0xee, 0x5d, 0xf0, 0xba, 0xb6, 0x65, 0xff, 0x77, 0xc0, 0x99, 0xd1, 0xca, 0xdc, 0xf5, 0x4b, 0x50, 0x50, 0x0a, 0x9e, 0x13, 0x33, 0x76, 0x86, 0x9b, 0x39, 0x79, 0x78, 0x73, 0x5c, 0x2f, 0x69, 0xa9, 0x9e, 0x0b, 0xeb, 0x11, 0x1e, 0x12, 0xaa, 0xc1, 0x09, 0x83, 0x0f, 0xca, 0xcb, 0x95, 0x10, 0xde, 0x85, 0xe3, 0x75, 0x62, 0x4a, 0xc2, 0x4c}, {0x68, 0x78, 0x6c, 0xce, 0x2f, 0x72, 0x80, 0xfe, 0x83, 0x88, 0x63, 0x37, 0xa7, 0xa1, 0x5a, 0x0b, 0x84, 0x8a, 0xda, 0x28, 0x84, 0xf1, 0x6a, 0x63, 0x24, 0x1c, 0x72, 0xda, 0x84, 0xee, 0x1d, 0xe0, 0x77, 0xf0, 0xf6, 0xce, 0x7e, 0x79, 0x0a, 0x55, 0x03, 0x01, 0x13, 0x0f, 0xf7, 0x6b, 0x45, 0xe7, 0xcb, 0xfd, 0xb0, 0x37, 0x93, 0x4b, 0x40, 0x69, 0xe0, 0x77, 0x67, 0x72, 0x65, 0xee, 0x35, 0x08, 0x00, 0xc0, 0x07, 0x10, 0xd8, 0x6e, 0x55, 0x83, 0x5a, 0xbc, 0xfa, 0x67, 0x80, 0x8f, 0xfa, 0x21, 0x3e, 0x56, 0x53, 0x5b, 0xbc, 0x9d, 0xff, 0x16, 0xd9, 0x57, 0xcf, 0x2b, 0x78, 0x06, 0x5a, 0x89}, {0xdf, 0x32, 0x1a, 0x01, 0x84, 0xe5, 0xb8, 0x2c, 0x70, 0x6c, 0xeb, 0xd1, 0xf0, 0xb4, 0x9b, 0x32, 0xc8, 0xd0, 0x81, 0xc4, 0xea, 0xb2, 0x7c, 0x32, 0x1a, 0x02, 0x61, 0xf2, 0xd9, 0x4d, 0xe5, 0x85, 0xad, 0xfc, 0xc6, 0x70, 0xee, 0x85, 0x77, 0x07, 0x9b, 0x5d, 0x5f, 0x88, 0xef, 0xb6, 0xd8, 0xdf, 0x2b, 0xa2, 0x4d, 0x90, 0x11, 0x2d, 0x38, 0x3f, 0xa8, 0x84, 0xf0, 0x76, 0xdd, 0x31, 0xd0, 0x09, 0x00, 0xc0, 0x07, 0x10, 0xd8, 0x6e, 0x55, 0x83, 0x5a, 0xbc, 0xfa, 0x67, 0x80, 0x8f, 0xfa, 0x21, 0x3e, 0x56, 0x53, 0x5b, 0xbc, 0x9d, 0xff, 0x16, 0xd9, 0x57, 0xcf, 0x2b, 0x78, 0x06, 0x5a, 0x89}}, - {{0x25, 0x87, 0x1e, 0x6f, 0xe8, 0xd0, 0xde, 0x1d, 0xd5, 0xf2, 0xd3, 0x5b, 0xff, 0x9e, 0x67, 0x99, 0x60, 0xb4, 0x0e, 0xb7, 0x98, 0x1b, 0x2a, 0x3a, 0x9c, 0xec, 0xc1, 0xe1, 0x2e, 0x2b, 0xc0, 0x3e, 0x3c, 0xfb, 0x64, 0x91, 0x72, 0xc6, 0x7e, 0x57, 0x47, 0x00, 0x97, 0xbf, 0x8e, 0x0e, 0xbf, 0xad, 0xd9, 0x28, 0x86, 0x7c, 0xfd, 0x41, 0x91, 0xae, 0x2d, 0xee, 0xc0, 0xb2, 0x32, 0x7d, 0x99, 0x7d}, {0x63, 0xc1, 0xf9, 0x61, 0x9c, 0x9e, 0x1a, 0xd7, 0xca, 0xa3, 0x71, 0xd6, 0x34, 0x3d, 0xa7, 0x08, 0x36, 0x0c, 0xec, 0x37, 0x35, 0x94, 0x1a, 0x45, 0xa9, 0xfa, 0xf2, 0xb5, 0x25, 0x92, 0xbf, 0xd1, 0x1e, 0xca, 0xdd, 0x5a, 0x23, 0xad, 0x9e, 0x45, 0xc3, 0x66, 0xcb, 0x8f, 0xda, 0xa3, 0xd1, 0xe6, 0x27, 0x38, 0x11, 0x54, 0x67, 0x31, 0x03, 0x64, 0x35, 0xe0, 0x68, 0x0b, 0x93, 0xee, 0x81, 0x17}, {0x8b, 0x01, 0xe9, 0x99, 0x54, 0x54, 0x73, 0x15, 0x0b, 0xac, 0x38, 0x7b, 0xe9, 0xe3, 0x17, 0x4f, 0x02, 0x3e, 0xe3, 0x8e, 0xda, 0x41, 0xa0, 0x9d, 0x10, 0xe0, 0xda, 0x11, 0xfe, 0xec, 0x2f, 0x42, 0xe7, 0xc8, 0xb3, 0xde, 0x2f, 0x7b, 0xfd, 0xdf, 0x7c, 0x34, 0x3b, 0x5e, 0xac, 0x22, 0x8c, 0x99, 0x3d, 0xa1, 0xa9, 0xd9, 0x81, 0xb6, 0x51, 0xc8, 0xaf, 0x3e, 0x75, 0xed, 0x45, 0xcf, 0xf7, 0xb9}, {0xaf, 0xe9, 0x9c, 0x16, 0x4a, 0x8f, 0x3b, 0x0f, 0xef, 0x71, 0x2f, 0xaa, 0x8d, 0x7d, 0xce, 0xed, 0xea, 0x31, 0x93, 0xaf, 0x2c, 0x75, 0xc6, 0xfa, 0xda, 0x3e, 0xa6, 0xea, 0x2a, 0x3e, 0x7b, 0x72, 0xb6, 0xf8, 0xd7, 0x9a, 0x88, 0xcb, 0x0b, 0x81, 0x97, 0x24, 0x29, 0x3b, 0x11, 0x23, 0x69, 0xc2, 0xff, 0x98, 0x39, 0x25, 0x99, 0xae, 0xe1, 0x07, 0x3e, 0x97, 0xde, 0x10, 0x21, 0x23, 0x7a, 0x2d}, {0xbe, 0x2f, 0xb9, 0x4c, 0x41, 0x5a, 0x9a, 0xf6, 0xfb, 0xf8, 0x26, 0x9d, 0x81, 0x7f, 0x39, 0x91, 0xaf, 0x5b, 0xf1, 0xd7, 0x93, 0x0a, 0xdf, 0x18, 0x19, 0x4a, 0x80, 0x74, 0x14, 0x98, 0x2b, 0xf2, 0x3b, 0x25, 0xc5, 0xe8, 0xfc, 0x07, 0x3f, 0x5d, 0xa1, 0x39, 0x27, 0x4e, 0x1c, 0xd2, 0x7a, 0xfe, 0x3e, 0x7b, 0x03, 0x35, 0x15, 0x9e, 0x35, 0x2b, 0xd0, 0xbe, 0x67, 0x48, 0x42, 0xdd, 0xa4, 0xdd}, {0xbd, 0xcd, 0xd7, 0xbf, 0xb1, 0x0a, 0xdb, 0x9f, 0x85, 0x42, 0xba, 0xf4, 0xc8, 0xff, 0xb0, 0xe1, 0x9a, 0x18, 0x6d, 0x1a, 0xe0, 0x37, 0xc1, 0xa2, 0xe1, 0x1c, 0x38, 0x55, 0x14, 0xbf, 0x64, 0x67, 0x84, 0x47, 0xb6, 0x0a, 0xf6, 0x93, 0xf1, 0x10, 0xab, 0x09, 0xf0, 0x60, 0x84, 0xe2, 0x4e, 0x4b, 0x5e, 0xa2, 0xd2, 0xd1, 0x19, 0x22, 0xd7, 0xc4, 0x85, 0x13, 0x23, 0xa3, 0x6a, 0xb6, 0x75, 0x0f, 0x43, 0xe6, 0xde, 0x7b, 0x67, 0x2a, 0x73, 0x77, 0x9e, 0xb4, 0x94, 0x6c, 0xc3, 0x9a, 0x67, 0x51, 0xcf, 0xe9, 0x47, 0x46, 0x0e, 0x3a, 0x12, 0x7d, 0x7c, 0x66, 0x73, 0x6c, 0xd5, 0x4a, 0x21, 0x4d}, {0x89, 0x7e, 0xd0, 0xbf, 0x2e, 0x9f, 0x0c, 0xff, 0x6e, 0x56, 0x25, 0x9b, 0x79, 0x99, 0x52, 0x27, 0xc2, 0x3a, 0xaa, 0xf0, 0x47, 0x6d, 0xed, 0x05, 0xa1, 0xeb, 0x9c, 0x92, 0x28, 0x7f, 0x1b, 0xc8, 0x1c, 0x57, 0x76, 0xab, 0x05, 0xe3, 0xd3, 0xb7, 0xa3, 0xf5, 0xac, 0xa8, 0x21, 0x33, 0x7c, 0xb7, 0xe7, 0xc2, 0xd0, 0x25, 0x6f, 0xdf, 0x34, 0xd1, 0xb0, 0x34, 0x41, 0x46, 0x30, 0x9c, 0x76, 0x07, 0x43, 0xe6, 0xde, 0x7b, 0x67, 0x2a, 0x73, 0x77, 0x9e, 0xb4, 0x94, 0x6c, 0xc3, 0x9a, 0x67, 0x51, 0xcf, 0xe9, 0x47, 0x46, 0x0e, 0x3a, 0x12, 0x7d, 0x7c, 0x66, 0x73, 0x6c, 0xd5, 0x4a, 0x21, 0x4d}} + { { 0xa1, 0xfc, 0x7a, 0xb4, 0x6d, 0xdf, 0x7d, 0xcf, 0xe7, 0xec, 0x75, 0xe5, 0xfa, 0xdd, 0x11, 0xcb, + 0xcc, 0x37, 0xf8, 0x84, 0x5d, 0x1c, 0x92, 0x4e, 0x09, 0x89, 0x65, 0xfc, 0xd8, 0xe9, 0x5a, 0x30, + 0xda, 0xe4, 0x86, 0xa3, 0x35, 0xb4, 0x19, 0x0c, 0xbc, 0x7b, 0xcb, 0x3e, 0xb9, 0x4c, 0xbd, 0x16, + 0xe8, 0x3d, 0x13, 0x2b, 0xc9, 0xc3, 0x39, 0xea, 0xf1, 0x42, 0xe7, 0x6f, 0x69, 0x78, 0x9a, 0xb7 }, + { 0xe5, 0xf3, 0x7b, 0xd4, 0x0e, 0xc9, 0xdc, 0x77, 0x50, 0x86, 0xdc, 0xf4, 0x2e, 0xbc, 0xdb, 0x27, + 0xf0, 0x73, 0xd4, 0x58, 0x73, 0xc4, 0x4b, 0x71, 0x8b, 0x3c, 0xc5, 0x4f, 0xa8, 0x7c, 0xa4, 0x84, + 0xd9, 0x96, 0x23, 0x73, 0xb4, 0x03, 0x16, 0xbf, 0x1e, 0xa1, 0x2d, 0xd8, 0xc4, 0x8a, 0xe7, 0x82, + 0x10, 0xda, 0xc9, 0xe5, 0x45, 0x9b, 0x01, 0xdc, 0x73, 0xa6, 0xc9, 0x17, 0xa8, 0x15, 0x31, 0x6d }, + { 0x3e, 0x49, 0xa4, 0x0e, 0x3a, 0xaf, 0xa3, 0x07, 0x3d, 0xf7, 0x2a, 0xec, 0x43, 0xb1, 0xd4, 0x09, + 0x1a, 0xcb, 0x8e, 0x92, 0xf9, 0x65, 0x95, 0x04, 0x6d, 0x2d, 0x9b, 0x34, 0xa3, 0xbf, 0x51, 0x00, + 0xe2, 0xee, 0x23, 0xf5, 0x28, 0x0a, 0xa9, 0xb1, 0x57, 0x0b, 0x96, 0x56, 0x62, 0xba, 0x12, 0x94, + 0xaf, 0xc6, 0x5f, 0xb5, 0x61, 0x43, 0x0f, 0xde, 0x0b, 0xab, 0xfa, 0x4f, 0xfe, 0xc5, 0xe7, 0x18 }, + { 0x00, 0x4d, 0x41, 0x8d, 0xe4, 0x69, 0x23, 0xae, 0x98, 0xc4, 0x3e, 0x77, 0x0f, 0x1d, 0x94, 0x5d, + 0x29, 0x3e, 0x94, 0x5a, 0x38, 0x39, 0x20, 0x0f, 0xd3, 0x6f, 0x76, 0xa2, 0x29, 0x02, 0x03, 0xcb, + 0x0b, 0x7f, 0x4f, 0x1a, 0x29, 0x51, 0x13, 0x33, 0x7c, 0x99, 0xb3, 0x81, 0x82, 0x39, 0x44, 0x05, + 0x97, 0xfb, 0x0d, 0xf2, 0x93, 0xa2, 0x40, 0x94, 0xf4, 0xff, 0x5d, 0x09, 0x61, 0xe4, 0x5f, 0x76 }, + { 0xab, 0xce, 0xd2, 0x24, 0xe8, 0x93, 0xb0, 0xe7, 0x72, 0x14, 0xdc, 0xbb, 0x7d, 0x0f, 0xd8, 0x94, + 0x16, 0x9e, 0xb5, 0x7f, 0xd7, 0x19, 0x5f, 0x3e, 0x2d, 0x45, 0xd5, 0xf7, 0x90, 0x0b, 0x3e, 0x05, + 0x18, 0x2e, 0x2b, 0xf4, 0xfa, 0xd4, 0xec, 0x62, 0x4a, 0x4f, 0x48, 0x50, 0xaf, 0x1c, 0xe8, 0x9f, + 0x1a, 0xe1, 0x3d, 0x70, 0x49, 0x00, 0xa7, 0xe3, 0x5b, 0x1e, 0xa1, 0x9b, 0x68, 0x1e, 0xa1, 0x73 }, + { 0xed, 0xb6, 0xd0, 0xf0, 0x06, 0x6e, 0x33, 0x9c, 0x86, 0xfb, 0xe8, 0xc3, 0x6c, 0x8d, 0xde, 0xdd, + 0xa6, 0xa0, 0x2d, 0xb9, 0x07, 0x29, 0xa3, 0x13, 0xbb, 0xa4, 0xba, 0xec, 0x48, 0xc8, 0xf4, 0x56, + 0x82, 0x79, 0xe2, 0xb1, 0xd3, 0x3d, 0x83, 0x9f, 0x10, 0xe8, 0x52, 0xe6, 0x8b, 0x1c, 0x33, 0x9e, + 0x2b, 0xd2, 0xdb, 0x62, 0x1c, 0x56, 0xfd, 0x50, 0x40, 0x77, 0x81, 0xab, 0x21, 0x67, 0x3e, 0x09, + 0x4f, 0xf2, 0x51, 0xac, 0x7d, 0xe7, 0xd1, 0x5d, 0x4b, 0xe2, 0x08, 0xc6, 0x3f, 0x6a, 0x4d, 0xc8, + 0x5d, 0x74, 0xf6, 0x3b, 0xec, 0x8e, 0xc6, 0x0c, 0x32, 0x27, 0x2f, 0x9c, 0x09, 0x48, 0x59, 0x10 }, + { 0x23, 0x0f, 0xa3, 0xe2, 0x69, 0xce, 0xb9, 0xb9, 0xd1, 0x1c, 0x4e, 0xab, 0x63, 0xc9, 0x2e, 0x1e, + 0x7e, 0xa2, 0xa2, 0xa0, 0x49, 0x2e, 0x78, 0xe4, 0x8a, 0x02, 0x3b, 0xa7, 0xab, 0x1f, 0xd4, 0xce, + 0x05, 0xe2, 0x80, 0x09, 0x09, 0x3c, 0x61, 0xc7, 0x10, 0x3a, 0x9c, 0xf4, 0x95, 0xac, 0x89, 0x6f, + 0x23, 0xb3, 0x09, 0xe2, 0x24, 0x3f, 0xf6, 0x96, 0x02, 0x36, 0x41, 0x16, 0x32, 0xe1, 0x66, 0x05, + 0x4f, 0xf2, 0x51, 0xac, 0x7d, 0xe7, 0xd1, 0x5d, 0x4b, 0xe2, 0x08, 0xc6, 0x3f, 0x6a, 0x4d, 0xc8, + 0x5d, 0x74, 0xf6, 0x3b, 0xec, 0x8e, 0xc6, 0x0c, 0x32, 0x27, 0x2f, 0x9c, 0x09, 0x48, 0x59, 0x10 } }, + { { 0xfd, 0x81, 0x14, 0xf1, 0x67, 0x07, 0x44, 0xbb, 0x93, 0x84, 0xa2, 0xdc, 0x36, 0xdc, 0xcc, 0xb3, + 0x9e, 0x82, 0xd4, 0x8b, 0x42, 0x56, 0xfb, 0xf2, 0x6e, 0x83, 0x3b, 0x16, 0x2c, 0x29, 0xfb, 0x39, + 0x29, 0x48, 0x85, 0xe3, 0xe3, 0xf7, 0xe7, 0x80, 0x49, 0xd3, 0x01, 0x30, 0x5a, 0x2c, 0x3f, 0x4c, + 0xea, 0x13, 0xeb, 0xda, 0xf4, 0x56, 0x75, 0x8d, 0x50, 0x1e, 0x19, 0x2d, 0x29, 0x2b, 0xfb, 0xdb }, + { 0x85, 0x34, 0x4d, 0xf7, 0x39, 0xbf, 0x98, 0x79, 0x8c, 0x98, 0xeb, 0x8d, 0x61, 0x27, 0xec, 0x87, + 0x56, 0xcd, 0xd0, 0xa6, 0x55, 0x77, 0xee, 0xf0, 0x20, 0xd0, 0x59, 0x39, 0x95, 0xab, 0x29, 0x82, + 0x8e, 0x61, 0xf8, 0xad, 0xed, 0xb6, 0x27, 0xc3, 0xd8, 0x16, 0xce, 0x67, 0x78, 0xe2, 0x04, 0x4b, + 0x0c, 0x2d, 0x2f, 0xc3, 0x24, 0x72, 0xbc, 0x53, 0xbd, 0xfe, 0x39, 0x23, 0xd4, 0xaf, 0x27, 0x84 }, + { 0x11, 0xbe, 0x5f, 0x5a, 0x73, 0xe7, 0x42, 0xef, 0xff, 0x3c, 0x47, 0x6a, 0x0e, 0x6b, 0x9e, 0x96, + 0x21, 0xa3, 0xdf, 0x49, 0xe9, 0x3f, 0x40, 0xfc, 0xab, 0xb3, 0x66, 0xd3, 0x3d, 0xfa, 0x02, 0x29, + 0xf3, 0x43, 0x45, 0x3c, 0x70, 0xa3, 0x5d, 0x39, 0xf7, 0xc0, 0x6a, 0xcd, 0xfa, 0x1d, 0xbe, 0x3b, + 0x91, 0x41, 0xe4, 0xb0, 0x60, 0xc0, 0x22, 0xf7, 0x2c, 0x11, 0x2b, 0x1c, 0x5f, 0x24, 0xef, 0x53 }, + { 0xfd, 0x3f, 0x09, 0x06, 0xc9, 0x39, 0x8d, 0x48, 0xfa, 0x6b, 0xc9, 0x80, 0xbf, 0xf6, 0xd6, 0x76, + 0xb3, 0x62, 0x70, 0x88, 0x4f, 0xde, 0xde, 0xb9, 0xb4, 0xf0, 0xce, 0xf3, 0x74, 0x0d, 0xea, 0x00, + 0x9e, 0x9c, 0x29, 0xe1, 0xa2, 0x1b, 0xbd, 0xb5, 0x83, 0xcc, 0x12, 0xd8, 0x48, 0x08, 0x5b, 0xe5, + 0xd6, 0xf9, 0x11, 0x5c, 0xe0, 0xd9, 0xc3, 0x3c, 0x26, 0xbd, 0x69, 0x9f, 0x5c, 0x6f, 0x0c, 0x6f }, + { 0xca, 0xd4, 0x76, 0x32, 0x8b, 0xbe, 0x0c, 0x65, 0x75, 0x43, 0x73, 0xc2, 0xf2, 0xfd, 0x7f, 0xeb, + 0xe4, 0x62, 0xc5, 0x0d, 0x0f, 0xf9, 0x01, 0xc8, 0xb9, 0xfa, 0xca, 0xb4, 0x12, 0x1c, 0xb4, 0xac, + 0x0e, 0x5f, 0x18, 0xfc, 0x0c, 0x7f, 0x2a, 0x55, 0xc5, 0xfd, 0x4d, 0x83, 0xb2, 0x02, 0x31, 0x6a, + 0x3f, 0x14, 0xee, 0x9d, 0x11, 0xa8, 0x06, 0xad, 0xeb, 0x93, 0x19, 0x79, 0xb1, 0xf2, 0x78, 0x05 }, + { 0x85, 0xe6, 0xe2, 0xf2, 0x96, 0xe7, 0xa2, 0x8b, 0x7e, 0x36, 0xbd, 0x7b, 0xf4, 0x28, 0x6a, 0xd7, + 0xbc, 0x2a, 0x6a, 0x59, 0xfd, 0xc0, 0xc8, 0x3d, 0x50, 0x0f, 0x0c, 0x2b, 0x12, 0x3a, 0x75, 0xc7, + 0x56, 0xbb, 0x7f, 0x7d, 0x4e, 0xd4, 0x03, 0xb8, 0x7b, 0xde, 0xde, 0x99, 0x65, 0x9e, 0xc4, 0xa6, + 0x6e, 0xfe, 0x00, 0x88, 0xeb, 0x9d, 0xa4, 0xa9, 0x9d, 0x37, 0xc9, 0x4a, 0xcf, 0x69, 0xc4, 0x01, + 0xba, 0xa8, 0xce, 0xeb, 0x72, 0xcb, 0x64, 0x8b, 0x9f, 0xc1, 0x1f, 0x9a, 0x9e, 0x99, 0xcc, 0x39, + 0xec, 0xd9, 0xbb, 0xd9, 0xce, 0xc2, 0x74, 0x6f, 0xd0, 0x2a, 0xb9, 0xc6, 0xe3, 0xf5, 0xe7, 0xf4 }, + { 0xb1, 0x39, 0x50, 0xb1, 0x1a, 0x08, 0x42, 0x2b, 0xdd, 0x6d, 0x20, 0x9f, 0x0f, 0x37, 0xba, 0x69, + 0x97, 0x21, 0x30, 0x7a, 0x71, 0x2f, 0xce, 0x98, 0x09, 0x04, 0xa2, 0x98, 0x6a, 0xed, 0x02, 0x1d, + 0x5d, 0x30, 0x8f, 0x03, 0x47, 0x6b, 0x89, 0xfd, 0xf7, 0x1a, 0xca, 0x46, 0x6f, 0x51, 0x69, 0x9a, + 0x2b, 0x18, 0x77, 0xe4, 0xad, 0x0d, 0x7a, 0x66, 0xd2, 0x2c, 0x28, 0xa0, 0xd3, 0x0a, 0x99, 0x0d, + 0xba, 0xa8, 0xce, 0xeb, 0x72, 0xcb, 0x64, 0x8b, 0x9f, 0xc1, 0x1f, 0x9a, 0x9e, 0x99, 0xcc, 0x39, + 0xec, 0xd9, 0xbb, 0xd9, 0xce, 0xc2, 0x74, 0x6f, 0xd0, 0x2a, 0xb9, 0xc6, 0xe3, 0xf5, 0xe7, 0xf4 } }, + { { 0x02, 0x3a, 0x7e, 0x0c, 0x6d, 0x96, 0x3c, 0x5d, 0x44, 0x56, 0x5d, 0xc1, 0x49, 0x94, 0x35, 0x12, + 0x9d, 0xff, 0x8a, 0x5d, 0x91, 0x74, 0xa8, 0x15, 0xee, 0x5d, 0x1e, 0x72, 0xbe, 0x86, 0x15, 0x68, + 0xe7, 0x36, 0xa2, 0x4a, 0xb8, 0xa2, 0xa4, 0x4c, 0xd8, 0x95, 0xe3, 0xc7, 0xbb, 0x32, 0x21, 0x90, + 0x64, 0x52, 0x32, 0xeb, 0x26, 0xd3, 0x4f, 0xf0, 0x8e, 0x27, 0x40, 0xea, 0xed, 0xdb, 0xf5, 0xc4 }, + { 0x76, 0x99, 0x64, 0x70, 0xf4, 0x50, 0xc8, 0xcc, 0x4a, 0x5a, 0xa5, 0x0f, 0xeb, 0x2d, 0xc7, 0x0e, + 0x73, 0xd0, 0x65, 0x7d, 0xc3, 0xce, 0x73, 0x03, 0x20, 0x2f, 0xad, 0x65, 0xfd, 0x12, 0xe4, 0x7f, + 0xfd, 0x45, 0x3a, 0x6e, 0xc5, 0x9a, 0x06, 0x67, 0x0e, 0xa6, 0x7b, 0x21, 0x49, 0x2d, 0x01, 0x1b, + 0x8e, 0x03, 0x6e, 0x10, 0x08, 0x0c, 0x68, 0xd9, 0x60, 0x47, 0xa4, 0xe2, 0x52, 0xfd, 0x3c, 0xf4 }, + { 0xa3, 0xe2, 0x5f, 0x16, 0x39, 0x78, 0x96, 0xf7, 0x47, 0x6f, 0x93, 0x5d, 0x27, 0x7b, 0x58, 0xe0, + 0xc5, 0xdb, 0x71, 0x7d, 0xa9, 0x6f, 0xf8, 0x8b, 0x69, 0xdd, 0x50, 0xea, 0x91, 0x0d, 0x66, 0x77, + 0xaf, 0x8f, 0xd5, 0x9f, 0x8a, 0x26, 0x69, 0x4c, 0x64, 0x37, 0x62, 0x81, 0x6f, 0x05, 0x9a, 0x08, + 0x0d, 0xe1, 0x69, 0x24, 0x77, 0x3f, 0x50, 0xb2, 0x49, 0x4d, 0x93, 0xef, 0x2e, 0x87, 0xff, 0xde }, + { 0xb3, 0x32, 0xe2, 0x67, 0x79, 0x32, 0x5f, 0x64, 0x47, 0x49, 0x1c, 0xd3, 0x8f, 0x95, 0x44, 0xfd, + 0x4c, 0x7e, 0xbf, 0x6b, 0xb7, 0xaf, 0x2c, 0xdd, 0x8f, 0xa5, 0xd8, 0x2f, 0xbf, 0xa0, 0x8a, 0x6b, + 0x58, 0x25, 0xc9, 0x12, 0x23, 0x6f, 0xe6, 0x05, 0xa8, 0xd0, 0x68, 0x6e, 0x0c, 0xee, 0x70, 0xe4, + 0xa3, 0x86, 0x51, 0x04, 0x6d, 0xca, 0xd5, 0xed, 0xcf, 0x74, 0x1d, 0x60, 0x9e, 0x86, 0x2d, 0x05 }, + { 0x91, 0xf4, 0x5f, 0x4a, 0xcb, 0xd8, 0xfd, 0x5f, 0xb9, 0x3d, 0x04, 0xb8, 0xec, 0x35, 0x85, 0x4f, + 0x58, 0x20, 0xd1, 0x1f, 0x47, 0xc4, 0xf4, 0xcb, 0x21, 0x4e, 0x9a, 0xf1, 0x6e, 0xbf, 0xe3, 0xd3, + 0x62, 0xe3, 0x82, 0xf6, 0xba, 0xa8, 0xdf, 0x92, 0xe2, 0x3c, 0xe5, 0xf0, 0x16, 0x8a, 0xeb, 0xa4, + 0xbb, 0xc7, 0x81, 0xaf, 0x15, 0x19, 0x87, 0x5f, 0xb7, 0xe0, 0x4c, 0x12, 0xff, 0x2c, 0xa9, 0xc8 }, + { 0xaf, 0x85, 0xe0, 0x36, 0x43, 0xdf, 0x41, 0x17, 0xda, 0xde, 0x5e, 0xb6, 0x33, 0xd0, 0xce, 0x62, + 0x70, 0x5f, 0x85, 0x24, 0x6c, 0x3e, 0x1b, 0xe1, 0x52, 0xc1, 0x9b, 0x1c, 0xcd, 0x61, 0x80, 0x9c, + 0xa0, 0xe8, 0x18, 0xee, 0x40, 0x91, 0x93, 0x82, 0xdb, 0x33, 0x44, 0xff, 0xd4, 0xf6, 0x6f, 0x5d, + 0xf0, 0x0e, 0x92, 0x92, 0x81, 0x55, 0x46, 0x06, 0xac, 0x58, 0x81, 0x3b, 0x04, 0xc7, 0xf7, 0x0d, + 0xd2, 0x0c, 0x08, 0x6d, 0x46, 0xdb, 0x43, 0x28, 0x31, 0xd8, 0xcd, 0x87, 0x50, 0xbb, 0xd3, 0x07, + 0xf5, 0x72, 0x0b, 0x15, 0x7c, 0x16, 0xab, 0x03, 0xd9, 0x4b, 0x07, 0x38, 0x97, 0xe8, 0xd6, 0xb5 }, + { 0x93, 0xff, 0x6d, 0xc3, 0x62, 0xf7, 0xcc, 0x20, 0x95, 0xc2, 0x2f, 0x7d, 0x1d, 0x9b, 0xd1, 0x63, + 0xfc, 0x61, 0x47, 0xb3, 0x22, 0x0f, 0xca, 0xb0, 0x16, 0xcf, 0x29, 0x53, 0x46, 0x97, 0xb1, 0x36, + 0x46, 0xac, 0x48, 0x13, 0x92, 0xe4, 0x46, 0x68, 0xcf, 0x09, 0x4e, 0xfa, 0x59, 0x45, 0x24, 0x08, + 0xdb, 0xb4, 0x6f, 0x20, 0x55, 0x12, 0xd9, 0x75, 0x9d, 0x8e, 0x0b, 0xf8, 0x63, 0xe0, 0xf9, 0x01, + 0xd2, 0x0c, 0x08, 0x6d, 0x46, 0xdb, 0x43, 0x28, 0x31, 0xd8, 0xcd, 0x87, 0x50, 0xbb, 0xd3, 0x07, + 0xf5, 0x72, 0x0b, 0x15, 0x7c, 0x16, 0xab, 0x03, 0xd9, 0x4b, 0x07, 0x38, 0x97, 0xe8, 0xd6, 0xb5 } }, + { { 0x14, 0x35, 0xa6, 0x7d, 0xc1, 0xb5, 0x71, 0xca, 0x42, 0x50, 0x90, 0xa7, 0x72, 0x85, 0xbe, 0x78, + 0x7a, 0x5f, 0x83, 0x1e, 0xbe, 0xef, 0x6a, 0xbe, 0x48, 0xc5, 0x68, 0x14, 0x0c, 0xf7, 0x44, 0x5c, + 0x2e, 0xfd, 0x1b, 0xcc, 0xee, 0x09, 0x23, 0x82, 0x31, 0xad, 0xaf, 0x4b, 0x73, 0x9c, 0xf2, 0x88, + 0x3c, 0xf3, 0xb5, 0x43, 0x8b, 0x53, 0xf9, 0xac, 0x17, 0x86, 0x1c, 0xc2, 0x53, 0x43, 0xec, 0x03 }, + { 0x7b, 0x36, 0x6c, 0xcc, 0xb5, 0xb2, 0x23, 0x3d, 0x7c, 0xe5, 0xe7, 0xcf, 0x06, 0xe2, 0x32, 0x0b, + 0xc5, 0x3b, 0x7f, 0x86, 0x40, 0xfc, 0xaf, 0xba, 0x94, 0xe0, 0x88, 0x58, 0x5b, 0xac, 0xe8, 0xc3, + 0xe8, 0xc3, 0xdf, 0xc4, 0x45, 0x29, 0xe8, 0xf0, 0x1c, 0x10, 0x0d, 0x50, 0x81, 0x29, 0x30, 0xa8, + 0x27, 0xb5, 0x3e, 0xb8, 0x25, 0xf1, 0x17, 0x30, 0xc6, 0x05, 0xe3, 0x3e, 0x45, 0x38, 0xa8, 0x3c }, + { 0xce, 0xd9, 0x45, 0x28, 0xb0, 0xce, 0xa5, 0x47, 0xa8, 0x29, 0x32, 0x76, 0x99, 0x73, 0x8d, 0x74, + 0xf9, 0xed, 0x0a, 0xd0, 0xf1, 0xd8, 0x7e, 0x44, 0x63, 0x9e, 0x9a, 0xcf, 0x7c, 0x35, 0x8a, 0x29, + 0xbb, 0x71, 0x66, 0x8d, 0xa7, 0xfc, 0x05, 0x3d, 0xd4, 0x4b, 0x65, 0x20, 0xf5, 0xa4, 0x64, 0xd8, + 0x9d, 0x16, 0x80, 0x9c, 0xb2, 0x3c, 0x3e, 0xd4, 0x9d, 0x09, 0x88, 0x8e, 0xbb, 0x58, 0xf8, 0x77 }, + { 0xe1, 0x29, 0xb3, 0x16, 0xe6, 0xa0, 0xdb, 0x64, 0x08, 0x36, 0xdc, 0x33, 0xad, 0x8b, 0x30, 0x26, + 0x17, 0x56, 0xd7, 0x34, 0x17, 0xd1, 0xdd, 0x23, 0x38, 0x58, 0x25, 0x01, 0x42, 0x5a, 0x9d, 0x18, + 0x3e, 0xac, 0x31, 0xfa, 0x43, 0x28, 0xc4, 0x65, 0xfb, 0x30, 0x2f, 0x8c, 0x16, 0x52, 0x32, 0x1b, + 0x19, 0xb7, 0x31, 0xf6, 0x67, 0xa7, 0xd8, 0xed, 0x9a, 0xa3, 0x95, 0x01, 0xd7, 0xb9, 0xe7, 0xcc }, + { 0x81, 0x2d, 0x11, 0xa9, 0x11, 0xf1, 0x22, 0xe2, 0x67, 0x70, 0xc4, 0xba, 0x34, 0xa1, 0x75, 0x8c, + 0xf6, 0x0c, 0x63, 0xe7, 0x01, 0x3c, 0x64, 0x6c, 0xe8, 0xd0, 0xf8, 0x8e, 0x88, 0xdf, 0x5c, 0x61, + 0x68, 0x5d, 0x1f, 0xeb, 0x83, 0x1f, 0x40, 0xb8, 0xa8, 0x56, 0x57, 0x26, 0x81, 0x2c, 0xa3, 0x0e, + 0x48, 0x4c, 0x45, 0x4d, 0x0d, 0x3d, 0x6e, 0x99, 0x52, 0xbd, 0x0b, 0xd8, 0x05, 0xc5, 0xf9, 0x61 }, + { 0x92, 0x45, 0xbe, 0xe6, 0xb4, 0x7a, 0xfa, 0x28, 0xd4, 0x5b, 0x6b, 0x17, 0xc6, 0x13, 0x61, 0x5d, + 0x5f, 0xd7, 0x90, 0xbb, 0x89, 0x35, 0x7a, 0x02, 0x50, 0x57, 0x56, 0x5f, 0x19, 0xb5, 0xb6, 0xc5, + 0x77, 0x1e, 0x1b, 0xc0, 0xd7, 0x7a, 0x29, 0xbd, 0xe7, 0x24, 0x01, 0x2d, 0x37, 0xc0, 0x38, 0x6f, + 0xc8, 0x35, 0xa1, 0x1b, 0xe0, 0xea, 0x16, 0xad, 0xbc, 0xdc, 0xd4, 0x8d, 0x4e, 0x71, 0xdb, 0x05, + 0x9e, 0xb5, 0x53, 0x6b, 0x5c, 0xf1, 0x7d, 0x15, 0x8b, 0xd7, 0xc7, 0x8b, 0x89, 0x9d, 0xfd, 0x28, + 0x7c, 0xa1, 0x31, 0xe2, 0xf0, 0x2c, 0x3a, 0x8d, 0x0e, 0x23, 0x85, 0x4e, 0xf0, 0xd1, 0xc0, 0x83 }, + { 0x7b, 0x88, 0xeb, 0x45, 0x1c, 0x7f, 0xfd, 0xbe, 0xba, 0xac, 0x53, 0x28, 0x59, 0xe8, 0xad, 0x28, + 0xf1, 0x97, 0x2d, 0x6c, 0x31, 0xa6, 0xae, 0x47, 0x10, 0x69, 0x68, 0x55, 0xa6, 0x9c, 0x03, 0x62, + 0xb7, 0x2f, 0x31, 0x46, 0x2a, 0x2b, 0x98, 0xdd, 0xe9, 0xf9, 0xfe, 0x77, 0x71, 0x41, 0x54, 0xf8, + 0x59, 0x02, 0x7a, 0xe3, 0x45, 0x67, 0xb6, 0xf7, 0x94, 0x31, 0x3e, 0x62, 0x62, 0x2a, 0xf9, 0x0a, + 0x9e, 0xb5, 0x53, 0x6b, 0x5c, 0xf1, 0x7d, 0x15, 0x8b, 0xd7, 0xc7, 0x8b, 0x89, 0x9d, 0xfd, 0x28, + 0x7c, 0xa1, 0x31, 0xe2, 0xf0, 0x2c, 0x3a, 0x8d, 0x0e, 0x23, 0x85, 0x4e, 0xf0, 0xd1, 0xc0, 0x83 } }, + { { 0x27, 0x4d, 0x84, 0x08, 0x95, 0x84, 0xc8, 0xeb, 0x1c, 0x9a, 0x0f, 0xca, 0x09, 0x6f, 0x48, 0x8b, + 0x2b, 0x06, 0xa0, 0xae, 0xf2, 0xe3, 0x8a, 0xfe, 0xd7, 0x52, 0x4b, 0xf2, 0xc6, 0x7c, 0xc1, 0x55, + 0x87, 0x2e, 0x5a, 0xb4, 0xc2, 0x43, 0x0a, 0x0d, 0xd0, 0x00, 0xa8, 0xe1, 0x46, 0x68, 0x79, 0xd8, + 0x8c, 0x01, 0x36, 0xb7, 0x5a, 0x61, 0x04, 0xe9, 0x7e, 0xbb, 0xc9, 0xee, 0xaa, 0x12, 0x13, 0xda }, + { 0x78, 0x66, 0xd0, 0xa2, 0x50, 0x82, 0x8d, 0xb0, 0xa0, 0x20, 0xac, 0xa4, 0xb6, 0xa0, 0x31, 0xf7, + 0x7d, 0x93, 0x37, 0x67, 0xbb, 0x60, 0xa2, 0x1e, 0x36, 0xce, 0x3d, 0x48, 0x1d, 0x79, 0x99, 0xa5, + 0x19, 0xd8, 0x89, 0x1b, 0xcb, 0x14, 0x87, 0xb7, 0x62, 0xfd, 0xd2, 0xef, 0xbb, 0x13, 0x41, 0x4d, + 0xf1, 0x77, 0x5c, 0x7f, 0x6c, 0x3b, 0x94, 0x7d, 0xb4, 0xba, 0x87, 0x3e, 0xc8, 0xe1, 0x3c, 0x0a }, + { 0xd9, 0x9e, 0x14, 0x89, 0xd6, 0xf8, 0x49, 0xa2, 0xe2, 0x19, 0xfe, 0x94, 0xaa, 0xf7, 0x35, 0xf9, + 0x4a, 0xf8, 0xf3, 0x18, 0x68, 0x96, 0x47, 0xc6, 0x23, 0x7c, 0xb0, 0x53, 0xcb, 0xd8, 0x90, 0x31, + 0xb7, 0x50, 0x0e, 0x06, 0xc3, 0x84, 0x75, 0xf1, 0xac, 0x16, 0x4d, 0xc1, 0xbe, 0xf1, 0x80, 0x33, + 0x47, 0x56, 0x6f, 0x33, 0x94, 0x5c, 0x81, 0x03, 0x4c, 0x2f, 0x6d, 0xac, 0x73, 0xba, 0x91, 0x3c }, + { 0x2f, 0xa9, 0xb6, 0xe8, 0x73, 0xe2, 0xef, 0x6d, 0x6d, 0xd7, 0x2e, 0xa0, 0x51, 0x61, 0x24, 0x81, + 0x8c, 0xa8, 0x47, 0x40, 0xe1, 0xc7, 0x75, 0x79, 0xc8, 0xec, 0xb2, 0x23, 0x41, 0xad, 0x61, 0x3b, + 0xea, 0x8a, 0xdf, 0x63, 0xed, 0xe1, 0x8e, 0x50, 0x70, 0x6e, 0x86, 0xed, 0xb0, 0xba, 0x27, 0x48, + 0x8e, 0xb9, 0x63, 0x39, 0x78, 0x58, 0x4f, 0x1e, 0xbc, 0x45, 0xf3, 0xf2, 0x3a, 0x73, 0x9b, 0x8c }, + { 0xad, 0x42, 0xc5, 0x84, 0xca, 0xe1, 0xe1, 0x23, 0x2a, 0x73, 0x15, 0x3c, 0x9a, 0xfe, 0x85, 0x8d, + 0xa3, 0x2c, 0xcf, 0x46, 0x8d, 0x7f, 0x1c, 0x61, 0xd7, 0x0e, 0xb1, 0xa6, 0xb4, 0xae, 0xab, 0x63, + 0xc4, 0x0e, 0xf2, 0xa0, 0x5d, 0xa6, 0xf3, 0x5d, 0x35, 0x41, 0xea, 0x03, 0x91, 0xb1, 0x3a, 0x07, + 0xe6, 0xed, 0x6c, 0x8c, 0xcb, 0x75, 0x27, 0xf1, 0x26, 0x58, 0xf0, 0x62, 0x57, 0xe4, 0x33, 0x00 }, + { 0x1f, 0xed, 0x53, 0xc6, 0xef, 0x38, 0x26, 0xa4, 0x18, 0x88, 0x8f, 0x5c, 0x49, 0x1c, 0x15, 0x7d, + 0x77, 0x90, 0x06, 0x39, 0xe0, 0x7c, 0x25, 0xed, 0x79, 0x05, 0x66, 0xe0, 0x5e, 0x94, 0xe3, 0x46, + 0x6f, 0x96, 0xd8, 0xc1, 0x11, 0xa4, 0x11, 0x6f, 0x78, 0x42, 0x8e, 0x89, 0xc7, 0xc3, 0xed, 0xd2, + 0x9e, 0x68, 0x47, 0x79, 0x89, 0x23, 0x70, 0x14, 0x21, 0x60, 0x2d, 0xfe, 0x37, 0x4b, 0xc8, 0x0a, + 0x16, 0x73, 0x7c, 0xc4, 0x55, 0x3f, 0x25, 0x04, 0x08, 0x75, 0x74, 0x68, 0xbc, 0xe4, 0x3a, 0xae, + 0x4c, 0x0e, 0xd2, 0x85, 0xa1, 0xbc, 0x81, 0xc0, 0xc9, 0xfe, 0x9a, 0x44, 0x7b, 0x83, 0xdf, 0xc7 }, + { 0x27, 0x77, 0x97, 0x84, 0x0f, 0x2d, 0x8d, 0x33, 0xb8, 0x4e, 0xdb, 0x8b, 0xea, 0x58, 0x52, 0x88, + 0x95, 0x88, 0x55, 0x5f, 0xb8, 0xc4, 0xc9, 0xd6, 0x1f, 0x1e, 0xee, 0x60, 0xb5, 0xeb, 0x78, 0x72, + 0xb5, 0xe5, 0x22, 0x2b, 0x7f, 0x5e, 0xc7, 0x9b, 0x29, 0x55, 0x8e, 0x2a, 0xfc, 0x65, 0x55, 0x4a, + 0x02, 0xad, 0x64, 0x06, 0xd4, 0x25, 0xe1, 0x96, 0x6f, 0xee, 0x96, 0xcd, 0x29, 0xc6, 0x64, 0x00, + 0x16, 0x73, 0x7c, 0xc4, 0x55, 0x3f, 0x25, 0x04, 0x08, 0x75, 0x74, 0x68, 0xbc, 0xe4, 0x3a, 0xae, + 0x4c, 0x0e, 0xd2, 0x85, 0xa1, 0xbc, 0x81, 0xc0, 0xc9, 0xfe, 0x9a, 0x44, 0x7b, 0x83, 0xdf, 0xc7 } }, + { { 0x5e, 0xc5, 0x5b, 0x9c, 0xdb, 0x14, 0x05, 0x18, 0x6b, 0xe2, 0x1d, 0x16, 0x77, 0x22, 0x0e, 0xd2, + 0xe4, 0x57, 0x82, 0x6e, 0x5b, 0xc5, 0x6a, 0xb9, 0x34, 0x20, 0xdb, 0x72, 0xe2, 0xe1, 0xeb, 0x1b, + 0x34, 0x00, 0x04, 0xbf, 0x83, 0xf6, 0x4f, 0x12, 0x45, 0x08, 0xf0, 0x95, 0x2a, 0xdc, 0x3a, 0x14, + 0xb3, 0x29, 0x0b, 0x99, 0xcd, 0x73, 0x31, 0xbd, 0x04, 0xbb, 0x49, 0x1c, 0xde, 0xcf, 0x09, 0x9e }, + { 0x15, 0x80, 0x3e, 0x2a, 0xfb, 0xc0, 0x8d, 0x62, 0x19, 0x27, 0x83, 0x04, 0xcc, 0xf5, 0xd1, 0xbb, + 0x40, 0x41, 0xbe, 0x93, 0x59, 0x6e, 0x27, 0x6d, 0x95, 0x24, 0x0a, 0x07, 0x27, 0x86, 0x10, 0x75, + 0xf7, 0x0a, 0x11, 0xfc, 0x53, 0xd0, 0x4c, 0x15, 0xf8, 0x6e, 0x22, 0x3f, 0xeb, 0x12, 0x97, 0x8a, + 0x3d, 0x69, 0xd8, 0x96, 0xc9, 0x53, 0x10, 0x9c, 0x02, 0x95, 0xe4, 0xd3, 0x1a, 0xd5, 0x43, 0x82 }, + { 0x40, 0x09, 0x2c, 0x17, 0x7e, 0xba, 0xce, 0x1f, 0xfc, 0xc1, 0x8e, 0xc3, 0x1c, 0xa2, 0x34, 0x52, + 0x78, 0x16, 0x23, 0x71, 0x82, 0x40, 0xf8, 0x6d, 0x67, 0x65, 0x67, 0x50, 0x53, 0xd9, 0xc8, 0x5e, + 0x7e, 0x8a, 0x98, 0xa3, 0xc6, 0x2a, 0x4d, 0x27, 0xf3, 0xb9, 0xbb, 0xae, 0x43, 0x29, 0x6e, 0x02, + 0x1c, 0xe9, 0x01, 0xd6, 0xcd, 0xd8, 0x91, 0x44, 0x95, 0x2b, 0x9e, 0xa5, 0x4f, 0xd0, 0x00, 0xb9 }, + { 0x3a, 0xe8, 0x3d, 0xb3, 0x32, 0xdc, 0xc2, 0xc8, 0xe3, 0x36, 0x2f, 0xc9, 0x30, 0x3a, 0xc0, 0x76, + 0x56, 0xd3, 0x0b, 0x06, 0xbe, 0x8f, 0xe7, 0xf1, 0x66, 0x61, 0x25, 0x42, 0x28, 0xdc, 0x08, 0x81, + 0x84, 0x3a, 0x57, 0x96, 0x27, 0xa6, 0xcf, 0xd6, 0x8f, 0x35, 0xa2, 0xc3, 0x76, 0x86, 0x4f, 0xcf, + 0x5f, 0xa1, 0x85, 0x28, 0x4f, 0x4a, 0x3a, 0xbb, 0x5c, 0x25, 0x4b, 0xcc, 0x46, 0xfe, 0xf2, 0x04 }, + { 0x62, 0xc8, 0xa2, 0x0a, 0x59, 0xb8, 0x97, 0xd2, 0x68, 0x94, 0x00, 0x3b, 0x01, 0xac, 0x91, 0x6e, + 0x97, 0x8e, 0x08, 0xe3, 0xfe, 0x9f, 0x9e, 0x9f, 0x4b, 0xcc, 0x5d, 0x1d, 0xb9, 0xbf, 0x07, 0x83, + 0xfe, 0x51, 0x2a, 0xdf, 0x79, 0x2e, 0x07, 0xc9, 0x98, 0x9b, 0xbe, 0xb6, 0xe4, 0x0a, 0x20, 0x44, + 0x86, 0xea, 0xb1, 0x61, 0x58, 0x11, 0x32, 0x8e, 0x7b, 0xb9, 0x67, 0x2d, 0xf0, 0x78, 0xb2, 0x93 }, + { 0x1a, 0x65, 0xb3, 0x6f, 0xa2, 0x45, 0x29, 0x53, 0xd7, 0x23, 0x4d, 0xff, 0x8e, 0xe9, 0xb9, 0xef, + 0x16, 0xa0, 0xdd, 0x48, 0xdf, 0x70, 0xd2, 0xe1, 0x56, 0xca, 0xd1, 0xd0, 0x4a, 0x9d, 0x63, 0x92, + 0x2b, 0xfd, 0x7b, 0x87, 0x39, 0x3c, 0x12, 0xc7, 0xe5, 0x91, 0x31, 0x95, 0x78, 0xc4, 0x58, 0x95, + 0x89, 0x6e, 0x2c, 0x90, 0xb4, 0x0b, 0xb2, 0xfe, 0x52, 0xc0, 0x86, 0xc4, 0x2e, 0x56, 0x97, 0x0c, + 0x20, 0xf2, 0xbc, 0x6a, 0x9b, 0x89, 0xfb, 0xe9, 0x85, 0x95, 0xd6, 0x22, 0x5e, 0x4d, 0x6d, 0x83, + 0x9d, 0xf4, 0xbe, 0x66, 0x05, 0x32, 0xb6, 0xe2, 0xf1, 0x96, 0x42, 0xa4, 0xc8, 0x8c, 0x1b, 0xec }, + { 0x43, 0x85, 0xff, 0xb9, 0xcf, 0x04, 0x83, 0x40, 0x70, 0x3a, 0x9c, 0x48, 0xb4, 0xc2, 0x99, 0x3b, + 0xa0, 0x39, 0xf1, 0x39, 0x58, 0x7f, 0xd2, 0x49, 0x94, 0x3c, 0xc3, 0xe1, 0xb6, 0x56, 0x38, 0x55, + 0x6f, 0xb5, 0x1a, 0x90, 0xa2, 0x04, 0x2f, 0x19, 0xf8, 0xb1, 0x65, 0x5a, 0xad, 0xcd, 0x1c, 0x56, + 0x42, 0x38, 0xc2, 0x52, 0x09, 0xd6, 0x41, 0x98, 0x5d, 0x5f, 0xa5, 0xe7, 0xc2, 0x55, 0xa1, 0x09, + 0x20, 0xf2, 0xbc, 0x6a, 0x9b, 0x89, 0xfb, 0xe9, 0x85, 0x95, 0xd6, 0x22, 0x5e, 0x4d, 0x6d, 0x83, + 0x9d, 0xf4, 0xbe, 0x66, 0x05, 0x32, 0xb6, 0xe2, 0xf1, 0x96, 0x42, 0xa4, 0xc8, 0x8c, 0x1b, 0xec } }, + { { 0xf2, 0x4a, 0x96, 0x57, 0xc3, 0x2f, 0xe6, 0x9f, 0xed, 0x7f, 0xcc, 0xe9, 0xea, 0xbe, 0xd2, 0x23, + 0x4e, 0x47, 0x13, 0xd9, 0x53, 0x19, 0x31, 0x14, 0x0a, 0xd3, 0x9b, 0x95, 0xa7, 0x9c, 0x88, 0x5e, + 0x08, 0xb2, 0x16, 0xda, 0x45, 0x61, 0x1d, 0x6b, 0xdf, 0xb1, 0x14, 0x0c, 0x66, 0xfd, 0x3a, 0xbe, + 0x25, 0xdc, 0xfd, 0xcd, 0xcc, 0x5e, 0x28, 0x77, 0x5a, 0xa9, 0x8b, 0x84, 0x77, 0x26, 0x9d, 0xa6 }, + { 0xea, 0xde, 0x4d, 0xab, 0x09, 0x02, 0xbf, 0x90, 0xf8, 0xae, 0x8b, 0x50, 0x01, 0xb2, 0x9d, 0x7c, + 0x0a, 0x3b, 0x60, 0xda, 0x34, 0xa9, 0xbb, 0x4d, 0xa5, 0x53, 0x18, 0x65, 0xec, 0xaa, 0xc9, 0x29, + 0xb2, 0xf7, 0x74, 0x14, 0x63, 0x5f, 0x88, 0xcf, 0x4e, 0x70, 0x1b, 0x11, 0x64, 0x73, 0x15, 0x6b, + 0x5a, 0x8c, 0xb8, 0x4e, 0x0f, 0x83, 0xae, 0x4b, 0x5c, 0x52, 0x1c, 0x6a, 0x0f, 0x54, 0x77, 0xc8 }, + { 0xae, 0xff, 0x55, 0xbf, 0x78, 0xb5, 0xde, 0x33, 0xeb, 0x87, 0xea, 0x13, 0x7d, 0x36, 0x22, 0x06, + 0x32, 0xc4, 0x7e, 0xca, 0x65, 0x37, 0xcc, 0x83, 0x0e, 0xda, 0x54, 0xb3, 0xd2, 0xe6, 0xe7, 0x7f, + 0xe1, 0x90, 0x11, 0x25, 0x16, 0x83, 0x25, 0x43, 0xb4, 0x38, 0x06, 0xbb, 0x6c, 0x62, 0x7d, 0x84, + 0x1f, 0xf3, 0x7b, 0xeb, 0xae, 0x50, 0xd8, 0xfb, 0xb9, 0xf2, 0xf9, 0xc3, 0x6f, 0x59, 0xb7, 0xb0 }, + { 0x95, 0x15, 0x83, 0x19, 0x56, 0x9c, 0x11, 0xd8, 0x31, 0x87, 0x1d, 0xe3, 0x3f, 0x07, 0x89, 0xb2, + 0xcb, 0x81, 0xf0, 0xeb, 0x0b, 0x1e, 0x74, 0x08, 0xa2, 0x4a, 0x0e, 0x82, 0xc6, 0x45, 0x8c, 0x32, + 0xb4, 0x8f, 0xfd, 0x76, 0xeb, 0x5e, 0xc7, 0x62, 0xdc, 0xcb, 0xee, 0xad, 0xcf, 0xcf, 0xea, 0x33, + 0x9d, 0xb0, 0x02, 0x64, 0x66, 0x77, 0x14, 0x97, 0x0c, 0x6e, 0x79, 0xe8, 0x58, 0x32, 0x0f, 0xe6 }, + { 0xcb, 0x2f, 0xaf, 0x53, 0xd8, 0x41, 0x48, 0x41, 0x6f, 0x36, 0x78, 0x80, 0x83, 0x5c, 0x0d, 0x4c, + 0x1b, 0xf4, 0x39, 0xe0, 0x34, 0x4f, 0xc2, 0xb2, 0x4e, 0xf0, 0xac, 0xc2, 0xf8, 0x15, 0x7a, 0x81, + 0x9f, 0x46, 0x2b, 0xe3, 0xb9, 0x39, 0x05, 0x89, 0xa2, 0xda, 0x1a, 0x63, 0x51, 0xb4, 0x78, 0x0f, + 0xfe, 0x2f, 0x9d, 0xce, 0x99, 0x38, 0xa9, 0x7e, 0xcb, 0x80, 0x57, 0x9f, 0xa2, 0x28, 0x0f, 0x6a }, + { 0x1b, 0xec, 0x67, 0x50, 0xd1, 0x28, 0x65, 0x55, 0xb8, 0xde, 0x3b, 0x2e, 0x1e, 0x33, 0xd8, 0x1b, + 0xba, 0x2e, 0x78, 0x6a, 0xb8, 0x0b, 0x8c, 0xa0, 0x55, 0x34, 0x25, 0x90, 0x9a, 0xe2, 0xf5, 0xaa, + 0x95, 0x0c, 0x6f, 0x2a, 0xb0, 0x92, 0x1d, 0x48, 0x5b, 0x56, 0x8c, 0x82, 0x8f, 0xa7, 0x15, 0x75, + 0x26, 0x61, 0x85, 0xc8, 0x7d, 0xda, 0xf5, 0x2a, 0xf3, 0x3c, 0x34, 0xc1, 0x20, 0x67, 0xbb, 0x04, + 0xec, 0x7c, 0xe2, 0xcb, 0x31, 0xcf, 0x23, 0xda, 0x5d, 0x8a, 0x05, 0x00, 0x9b, 0x23, 0x34, 0xd0, + 0xed, 0x56, 0x10, 0x0a, 0x90, 0x6b, 0x73, 0x26, 0x6b, 0xf0, 0xd7, 0xbc, 0xd8, 0xc7, 0x89, 0xc8 }, + { 0x90, 0x43, 0x54, 0x87, 0x44, 0x00, 0x07, 0xca, 0xa8, 0x2b, 0xec, 0x55, 0xa0, 0xd2, 0x8c, 0x07, + 0x03, 0xaa, 0x61, 0x1a, 0x7d, 0x0f, 0x90, 0x13, 0x67, 0x99, 0x46, 0x20, 0xcd, 0x70, 0xcb, 0xa7, + 0x96, 0xdf, 0x0c, 0x13, 0xc4, 0x41, 0x11, 0xd6, 0xc3, 0x33, 0x02, 0x96, 0x4f, 0x1d, 0xbd, 0x06, + 0xa9, 0xa1, 0x31, 0x0a, 0xc3, 0xdf, 0x6d, 0x52, 0x6c, 0xc6, 0xbe, 0xc5, 0xb6, 0x2a, 0xb1, 0x0f, + 0xec, 0x7c, 0xe2, 0xcb, 0x31, 0xcf, 0x23, 0xda, 0x5d, 0x8a, 0x05, 0x00, 0x9b, 0x23, 0x34, 0xd0, + 0xed, 0x56, 0x10, 0x0a, 0x90, 0x6b, 0x73, 0x26, 0x6b, 0xf0, 0xd7, 0xbc, 0xd8, 0xc7, 0x89, 0xc8 } }, + { { 0x4f, 0x3a, 0xdd, 0x0f, 0xcf, 0x7f, 0x27, 0xda, 0x27, 0xc4, 0xa6, 0x2b, 0x6b, 0xd1, 0x9f, 0x59, + 0x73, 0x5f, 0xd4, 0xb7, 0xf0, 0x86, 0x16, 0xc9, 0xdd, 0xa6, 0xf9, 0x9b, 0x17, 0xb2, 0xb9, 0x71, + 0xe7, 0x4c, 0xa1, 0x17, 0x79, 0xe0, 0xcc, 0xae, 0x10, 0xec, 0x28, 0x3a, 0x09, 0xf2, 0x8b, 0x34, + 0x9c, 0xac, 0x16, 0x2a, 0xa9, 0x21, 0xe8, 0xa7, 0x18, 0xc0, 0xc4, 0x9f, 0x30, 0xa0, 0x25, 0x62 }, + { 0x23, 0x4c, 0xd4, 0xae, 0x52, 0x30, 0xf6, 0x64, 0xb9, 0xe1, 0x47, 0xca, 0xf8, 0xf3, 0x3a, 0x6b, + 0x8b, 0xf3, 0x29, 0xe2, 0x9b, 0x5d, 0xbb, 0x0a, 0x60, 0x52, 0x03, 0x40, 0x53, 0x5c, 0x9e, 0x35, + 0x03, 0xd4, 0xec, 0xd7, 0x67, 0xf4, 0x92, 0xd2, 0x98, 0x96, 0xf2, 0xa7, 0xf4, 0x25, 0x6a, 0x80, + 0x9c, 0x75, 0xc6, 0xf2, 0x1f, 0x67, 0x11, 0x00, 0x0d, 0xda, 0x1e, 0xb2, 0x58, 0xa7, 0x8c, 0x39 }, + { 0x55, 0x1b, 0x80, 0xbb, 0xf3, 0xc5, 0x1a, 0x84, 0x34, 0xf5, 0x0a, 0x8a, 0x8a, 0xe1, 0x8c, 0xea, + 0xa6, 0xfb, 0xd0, 0x26, 0xc9, 0xa2, 0x30, 0x37, 0x3e, 0xba, 0x98, 0xfe, 0x81, 0x8a, 0x52, 0x37, + 0x0b, 0x74, 0x4e, 0x3d, 0x26, 0x8f, 0x82, 0x4b, 0xc0, 0x6a, 0x01, 0x10, 0x91, 0x8f, 0x89, 0xb5, + 0x62, 0x3f, 0x1e, 0x70, 0xcc, 0x25, 0x77, 0x39, 0x74, 0x88, 0xdd, 0xbc, 0xbe, 0x72, 0x08, 0x63 }, + { 0xe2, 0x9a, 0x46, 0xd2, 0x74, 0xdc, 0x0f, 0x8a, 0xa3, 0xbd, 0x20, 0xb7, 0xc7, 0xd9, 0x83, 0x4b, + 0x58, 0xa6, 0xe3, 0xbd, 0xc5, 0x00, 0xb6, 0x18, 0x04, 0x25, 0x81, 0xbd, 0x99, 0xb3, 0xb1, 0x2a, + 0x7a, 0x68, 0x6d, 0xe1, 0x3e, 0x23, 0x8d, 0x29, 0x9e, 0x7a, 0x30, 0x56, 0x4c, 0x22, 0xb6, 0xf4, + 0x7d, 0x7d, 0x4f, 0xfd, 0x76, 0xa5, 0x9d, 0x05, 0x41, 0x7c, 0x7a, 0x2d, 0x7b, 0xbe, 0xcf, 0x73 }, + { 0x7b, 0xae, 0x11, 0x86, 0x8a, 0x38, 0xbd, 0x56, 0x3c, 0xf3, 0x3c, 0x9c, 0x49, 0xa4, 0x68, 0x0f, + 0x2b, 0xdf, 0xf2, 0xa1, 0xbc, 0xc2, 0xed, 0x08, 0x09, 0x96, 0xd0, 0x7e, 0x9b, 0xe3, 0x0a, 0x72, + 0x13, 0x03, 0xd4, 0x35, 0x0a, 0x94, 0x60, 0x09, 0x4a, 0xaa, 0xca, 0x35, 0x8e, 0xed, 0x12, 0xdd, + 0x26, 0x8f, 0xf8, 0xa9, 0xa2, 0x8a, 0x7f, 0xac, 0xf3, 0x09, 0xc7, 0x22, 0xc5, 0x73, 0xec, 0xa0 }, + { 0xe9, 0xc5, 0x57, 0x0d, 0x85, 0xbf, 0x10, 0xe2, 0xd1, 0xf5, 0xd7, 0x22, 0xe9, 0x6a, 0x67, 0x8d, + 0xd3, 0x9f, 0x1a, 0xef, 0x7f, 0xc0, 0x2b, 0xe1, 0xfd, 0x2c, 0xc2, 0x5f, 0x39, 0xf9, 0x34, 0xd0, + 0x87, 0x94, 0x41, 0x8a, 0x65, 0xa5, 0x20, 0x48, 0xa4, 0x20, 0x5f, 0x7a, 0xc7, 0x37, 0x00, 0x60, + 0x59, 0x84, 0x2a, 0x1d, 0xff, 0x02, 0xc3, 0xe8, 0x20, 0xaa, 0x39, 0x13, 0xac, 0xf3, 0xd7, 0x05, + 0xbd, 0xef, 0x11, 0x66, 0x71, 0xb8, 0x9f, 0x1e, 0xe5, 0xee, 0x2e, 0x37, 0xfb, 0x34, 0xed, 0xc5, + 0xa4, 0x40, 0x6e, 0x38, 0x31, 0x0a, 0x1c, 0xaf, 0x0d, 0xd3, 0x98, 0xac, 0x12, 0x40, 0xea, 0x9c }, + { 0xc6, 0xcd, 0x7a, 0xbd, 0x14, 0xdb, 0xe4, 0xed, 0xbf, 0x46, 0x70, 0x23, 0xbd, 0xdb, 0xc3, 0xce, + 0x60, 0xd5, 0x6b, 0x17, 0x4c, 0x23, 0xfa, 0x78, 0x05, 0xcc, 0x18, 0xed, 0x42, 0x03, 0xa5, 0xb7, + 0xdf, 0x28, 0x0e, 0xd4, 0x5d, 0x31, 0xd8, 0xb9, 0xdc, 0xe9, 0xf6, 0x26, 0xc5, 0xe1, 0xb3, 0x80, + 0x0d, 0x62, 0xaf, 0x2d, 0xbd, 0xd6, 0xe4, 0xbb, 0x16, 0x82, 0xc8, 0x13, 0x2a, 0x6f, 0xb9, 0x06, + 0xbd, 0xef, 0x11, 0x66, 0x71, 0xb8, 0x9f, 0x1e, 0xe5, 0xee, 0x2e, 0x37, 0xfb, 0x34, 0xed, 0xc5, + 0xa4, 0x40, 0x6e, 0x38, 0x31, 0x0a, 0x1c, 0xaf, 0x0d, 0xd3, 0x98, 0xac, 0x12, 0x40, 0xea, 0x9c } }, + { { 0x6f, 0x46, 0xcd, 0x96, 0xc4, 0x13, 0xf4, 0x11, 0x62, 0x49, 0x8c, 0x5c, 0x78, 0x27, 0xef, 0xc8, + 0xb9, 0xe2, 0x7d, 0xf1, 0x0d, 0x37, 0xf2, 0xfe, 0x85, 0x35, 0x82, 0x60, 0x23, 0xb6, 0x7b, 0x17, + 0xd2, 0x91, 0xef, 0x01, 0x9e, 0x99, 0x35, 0xab, 0xc7, 0xfb, 0xa1, 0xa3, 0x13, 0x44, 0x3f, 0x3c, + 0x16, 0xcb, 0xd8, 0xf0, 0xbf, 0x9e, 0x65, 0x4d, 0x07, 0xe0, 0xfd, 0x8e, 0x32, 0x61, 0x95, 0xd5 }, + { 0xb7, 0x81, 0x16, 0x2f, 0xcb, 0xa4, 0x30, 0x4e, 0x6d, 0xf5, 0xf0, 0x3f, 0xfe, 0xd9, 0x81, 0x20, + 0xa6, 0x0e, 0x2b, 0xa8, 0xc5, 0xed, 0x0d, 0x9a, 0x28, 0x9c, 0xe3, 0xa9, 0xb7, 0xbf, 0x87, 0x0f, + 0xa5, 0xf9, 0x33, 0xe7, 0xa6, 0x7f, 0x9b, 0xac, 0xb6, 0xcc, 0xaf, 0xfc, 0xa7, 0x4a, 0x4d, 0x36, + 0x39, 0xa9, 0xb6, 0xf5, 0x09, 0xde, 0x8d, 0x37, 0x11, 0x07, 0xd1, 0x8a, 0xf5, 0x7b, 0x66, 0xe1 }, + { 0xcc, 0xe0, 0x07, 0x62, 0xbe, 0x10, 0x8c, 0x3a, 0xa2, 0x96, 0x5d, 0x11, 0xc7, 0xd5, 0x50, 0xc3, + 0xbb, 0x55, 0x21, 0xc5, 0x40, 0x27, 0x7d, 0xdb, 0xad, 0xd2, 0x61, 0x2a, 0x42, 0x5f, 0x94, 0x23, + 0x77, 0x83, 0x3a, 0x99, 0xe8, 0xda, 0x79, 0x8c, 0x1e, 0xa8, 0x44, 0x04, 0xec, 0xf5, 0xd1, 0x55, + 0x1e, 0x58, 0xf1, 0x6e, 0x4d, 0x27, 0xa4, 0x91, 0xec, 0x59, 0xc8, 0x17, 0x36, 0x58, 0x2a, 0x1f }, + { 0x6d, 0xf8, 0x73, 0xa3, 0x38, 0x61, 0x1d, 0x95, 0x09, 0xde, 0xe5, 0x26, 0x1b, 0x15, 0x16, 0xfb, + 0xf5, 0x16, 0xa8, 0xf3, 0x9e, 0x3a, 0x6b, 0xb5, 0x8c, 0xee, 0xa8, 0x66, 0x79, 0xc3, 0x9e, 0xb4, + 0xe1, 0xc2, 0x85, 0x0e, 0x86, 0x10, 0x5a, 0x4e, 0x8b, 0x4c, 0x0a, 0x7a, 0xd8, 0x8a, 0x48, 0xf4, + 0xa0, 0x79, 0x37, 0xe3, 0xa5, 0x90, 0x05, 0x5e, 0xbd, 0xa1, 0xf6, 0x09, 0x58, 0x9c, 0x6f, 0x09 }, + { 0x66, 0x47, 0x6d, 0x60, 0x06, 0x2d, 0x90, 0x8f, 0xae, 0x6c, 0x01, 0xe9, 0xb0, 0xf9, 0x6b, 0xa5, + 0x4a, 0xe1, 0xdb, 0xd3, 0x64, 0x42, 0x37, 0x5c, 0x11, 0x40, 0x7a, 0xce, 0x4e, 0x83, 0xc3, 0x2c, + 0x2e, 0xd2, 0x67, 0x76, 0xfb, 0x8c, 0x5d, 0xab, 0xe8, 0xb8, 0xd6, 0x2b, 0xf8, 0x86, 0xff, 0x96, + 0xf3, 0xa8, 0x0e, 0x2b, 0x1a, 0x68, 0xf5, 0xe4, 0xee, 0x49, 0xa6, 0x8c, 0x41, 0x1f, 0x97, 0xbf }, + { 0x81, 0x92, 0x4e, 0xc6, 0xab, 0x00, 0xdd, 0xf9, 0xf9, 0xb7, 0xe0, 0x0a, 0xa9, 0x3f, 0x0a, 0xf9, + 0x32, 0x73, 0xf6, 0x22, 0xec, 0x95, 0xd9, 0x20, 0x8a, 0x3f, 0xeb, 0x0d, 0xc7, 0x79, 0x6f, 0xb3, + 0x85, 0xf4, 0xe1, 0x11, 0xe1, 0xcc, 0xaa, 0x1b, 0xfd, 0xf3, 0x43, 0xff, 0x66, 0x73, 0x0f, 0x09, + 0xcc, 0xa4, 0x6c, 0xb8, 0x2a, 0x0f, 0x53, 0x58, 0x63, 0x32, 0x06, 0xd9, 0x6b, 0x1a, 0x14, 0x04, + 0x85, 0x3f, 0x2f, 0x2b, 0x05, 0xfb, 0xed, 0xe9, 0x08, 0x0d, 0x21, 0x49, 0xc9, 0x79, 0xdf, 0x6f, + 0x77, 0x89, 0xd7, 0x74, 0x09, 0x57, 0x1a, 0xd2, 0xa7, 0x43, 0xbf, 0x08, 0x8e, 0x98, 0xbc, 0x2f }, + { 0xe3, 0xb1, 0xc4, 0x81, 0xe6, 0xec, 0x07, 0x58, 0xa4, 0xcb, 0x7e, 0xd5, 0xae, 0x9d, 0x43, 0xf1, + 0xb7, 0xe2, 0x0a, 0x1f, 0xd5, 0xe8, 0x14, 0xba, 0x22, 0xff, 0xb7, 0x20, 0x76, 0x08, 0xdc, 0x9a, + 0x44, 0x4c, 0x1c, 0xcd, 0x38, 0x4d, 0xb5, 0xd8, 0xa9, 0x1b, 0x9d, 0xbb, 0x13, 0x5a, 0x6c, 0xe9, + 0x5d, 0xa4, 0x42, 0x0e, 0xde, 0x9a, 0x47, 0x8a, 0x2a, 0x97, 0x42, 0x86, 0x87, 0x98, 0x3f, 0x04, + 0x85, 0x3f, 0x2f, 0x2b, 0x05, 0xfb, 0xed, 0xe9, 0x08, 0x0d, 0x21, 0x49, 0xc9, 0x79, 0xdf, 0x6f, + 0x77, 0x89, 0xd7, 0x74, 0x09, 0x57, 0x1a, 0xd2, 0xa7, 0x43, 0xbf, 0x08, 0x8e, 0x98, 0xbc, 0x2f } }, + { { 0xff, 0xe3, 0x69, 0x7b, 0x62, 0x45, 0x40, 0x5f, 0x1c, 0x49, 0x65, 0xd6, 0xae, 0x24, 0x16, 0x84, + 0xfa, 0x69, 0x6c, 0x1f, 0x6c, 0x65, 0xee, 0x52, 0xe9, 0x6c, 0x54, 0xc7, 0x31, 0x9b, 0xc2, 0x74, + 0x4f, 0xc0, 0x16, 0xb8, 0xf8, 0x75, 0x5f, 0x45, 0xb5, 0xf3, 0xa0, 0xd9, 0xbe, 0x25, 0x82, 0xbd, + 0x3c, 0x03, 0xe0, 0x14, 0x15, 0x6a, 0xd5, 0x64, 0x08, 0x65, 0x13, 0x33, 0xc2, 0xab, 0xe0, 0x45 }, + { 0x6f, 0x5a, 0x90, 0x80, 0x25, 0x13, 0xc2, 0xa7, 0xfe, 0x1c, 0xa1, 0x07, 0x81, 0x4b, 0x09, 0xd3, + 0xbd, 0xda, 0x55, 0xa8, 0xaa, 0x62, 0x19, 0x03, 0xe9, 0x9f, 0x77, 0xef, 0xff, 0xd4, 0x5e, 0x53, + 0xbc, 0x9d, 0x71, 0xb8, 0xc4, 0xc2, 0x85, 0xb9, 0xb4, 0x3d, 0x95, 0xb8, 0xfd, 0x44, 0xb7, 0xc8, + 0x6f, 0x93, 0x15, 0x04, 0x16, 0x7e, 0x01, 0xf2, 0x09, 0x23, 0x96, 0x69, 0xe5, 0x65, 0x52, 0x34 }, + { 0xaf, 0xfe, 0x4f, 0x34, 0x4e, 0xfe, 0x51, 0xa5, 0xb2, 0xd8, 0x31, 0x74, 0x7b, 0xae, 0xfb, 0xb9, + 0x33, 0xc1, 0xdc, 0x66, 0xe6, 0x95, 0x9e, 0xce, 0x77, 0x7d, 0x55, 0x3c, 0xa6, 0x6c, 0x09, 0x23, + 0x5a, 0x1a, 0x5e, 0x1a, 0x41, 0xd3, 0xad, 0x5f, 0x86, 0xd0, 0x14, 0xf5, 0xe0, 0xda, 0xf1, 0xce, + 0x19, 0x90, 0x45, 0x0c, 0x4c, 0xb1, 0xd3, 0xc8, 0x4c, 0xdb, 0x7e, 0x49, 0xf5, 0xac, 0xde, 0xff }, + { 0x1b, 0x9b, 0x6b, 0x30, 0xd3, 0x19, 0x37, 0x83, 0xad, 0x05, 0xca, 0xba, 0x22, 0x85, 0x33, 0x7f, + 0x55, 0x60, 0xe3, 0x14, 0x8c, 0x39, 0x87, 0xd1, 0x4c, 0x21, 0x27, 0xa0, 0xae, 0x4a, 0x56, 0x15, + 0x50, 0x6c, 0x99, 0xca, 0xff, 0xde, 0x10, 0xc6, 0x9f, 0x6c, 0x70, 0xd1, 0x66, 0xb4, 0x87, 0xd8, + 0xfc, 0x46, 0xf2, 0xcf, 0x0c, 0xd8, 0xc3, 0x14, 0x5d, 0x27, 0xbd, 0xed, 0x32, 0x36, 0x7c, 0xed }, + { 0x64, 0x6b, 0x74, 0xc7, 0x60, 0x36, 0xc5, 0xe4, 0xb6, 0xde, 0x02, 0x1a, 0x09, 0xaf, 0x65, 0xb1, + 0x94, 0xa3, 0xf4, 0x95, 0xf5, 0xb0, 0xef, 0x86, 0xb5, 0x13, 0x26, 0x0b, 0xe8, 0xc5, 0x5c, 0x77, + 0xf5, 0xe6, 0xb6, 0x10, 0x36, 0x87, 0xa3, 0xd2, 0x7c, 0x17, 0x2c, 0xb9, 0xb0, 0x90, 0x9e, 0x8c, + 0x0a, 0x7d, 0x73, 0xb2, 0x29, 0xeb, 0xa7, 0x85, 0xd7, 0x04, 0x14, 0xf9, 0x77, 0xb7, 0xf4, 0x89 }, + { 0x7f, 0x1c, 0x5a, 0x57, 0x14, 0xf6, 0x30, 0x07, 0xf9, 0xfe, 0x42, 0x98, 0xcb, 0x3d, 0xac, 0x04, + 0x30, 0x0d, 0xc6, 0xd0, 0x4f, 0x8a, 0xbc, 0xdd, 0x3e, 0xc3, 0xb7, 0x74, 0xc8, 0x3b, 0x1a, 0xcc, + 0x6a, 0x54, 0x9e, 0xb9, 0xbe, 0xf0, 0x7c, 0x35, 0x35, 0x1a, 0x50, 0x4c, 0xc2, 0x38, 0x41, 0x46, + 0xc8, 0xc4, 0x81, 0x2b, 0x26, 0x56, 0x6f, 0x8a, 0x9f, 0x74, 0x87, 0xe0, 0x01, 0x82, 0xe2, 0x09, + 0xf3, 0x9a, 0xc5, 0x33, 0x5a, 0x7d, 0xb6, 0xbb, 0xff, 0x20, 0x4d, 0xc1, 0x99, 0x3d, 0xcc, 0x5a, + 0xc7, 0xd1, 0xbe, 0x4c, 0xcf, 0xc8, 0x09, 0x79, 0x15, 0x5e, 0x0c, 0xc6, 0x26, 0x36, 0xe6, 0xd9 }, + { 0x4d, 0x2f, 0x08, 0x84, 0x32, 0xcf, 0xe0, 0x3b, 0xa8, 0x3e, 0xa5, 0xf8, 0x3a, 0xe8, 0xa9, 0x04, + 0x5a, 0x74, 0x67, 0xcb, 0x41, 0x22, 0xc5, 0xc4, 0x9a, 0xa5, 0xc1, 0xa7, 0x94, 0x8b, 0xa5, 0x35, + 0x00, 0x00, 0x1a, 0xaf, 0xfb, 0xed, 0x40, 0xb8, 0x2b, 0x28, 0xf1, 0xb1, 0x02, 0xd3, 0x8b, 0xc0, + 0x32, 0x4a, 0xa5, 0x0a, 0xa4, 0xc3, 0xbf, 0xb3, 0xf5, 0xb7, 0x65, 0x8e, 0x88, 0xdf, 0xd0, 0x0e, + 0xf3, 0x9a, 0xc5, 0x33, 0x5a, 0x7d, 0xb6, 0xbb, 0xff, 0x20, 0x4d, 0xc1, 0x99, 0x3d, 0xcc, 0x5a, + 0xc7, 0xd1, 0xbe, 0x4c, 0xcf, 0xc8, 0x09, 0x79, 0x15, 0x5e, 0x0c, 0xc6, 0x26, 0x36, 0xe6, 0xd9 } }, + { { 0xc8, 0x8e, 0x1c, 0xea, 0x02, 0x6a, 0xfd, 0x88, 0x8b, 0xa9, 0x9d, 0xdd, 0xba, 0xea, 0x77, 0x30, + 0x88, 0x1a, 0x93, 0x49, 0xda, 0x05, 0x18, 0xbb, 0x4a, 0x6a, 0x11, 0xc4, 0x48, 0x72, 0x77, 0x1f, + 0x6e, 0x2b, 0x9a, 0xe3, 0x27, 0xbe, 0xe1, 0x75, 0x32, 0x30, 0xa6, 0x12, 0x26, 0x44, 0xbf, 0xb2, + 0xa5, 0x51, 0x0b, 0x48, 0x3a, 0xea, 0xc5, 0xd4, 0x24, 0x3f, 0x4e, 0xe8, 0xe5, 0xc3, 0xfb, 0xc2 }, + { 0xcb, 0x56, 0x3c, 0x00, 0x28, 0x15, 0x72, 0x16, 0x23, 0x4e, 0x2e, 0x2c, 0x8c, 0xe8, 0x7c, 0x44, + 0x82, 0x2a, 0xe0, 0x57, 0xa3, 0x0a, 0xc4, 0x42, 0xb5, 0x07, 0xe1, 0x1b, 0x78, 0x8b, 0x3d, 0x4d, + 0xcb, 0xe4, 0x56, 0x72, 0x0b, 0x85, 0x52, 0xd8, 0x55, 0xe2, 0xcd, 0x38, 0xd2, 0x83, 0xb6, 0x05, + 0xd2, 0x9f, 0x63, 0x9e, 0x7f, 0xca, 0xe5, 0x95, 0x36, 0x61, 0x9b, 0xca, 0x09, 0x27, 0x53, 0x82 }, + { 0x24, 0x67, 0x10, 0xd6, 0x8a, 0x1a, 0x8e, 0xb8, 0x53, 0xef, 0xb7, 0x67, 0x2a, 0xfd, 0xb8, 0xd6, + 0xe3, 0xf7, 0x41, 0x95, 0x8c, 0x50, 0xca, 0x1d, 0x21, 0x21, 0x41, 0xd1, 0xef, 0x2d, 0x9b, 0x53, + 0xa9, 0x42, 0xcd, 0xda, 0x6d, 0x12, 0x1b, 0xbd, 0x0a, 0xe1, 0x4d, 0x95, 0xc6, 0xaa, 0x40, 0xfd, + 0x98, 0xfb, 0x26, 0x21, 0x5e, 0xaf, 0x8e, 0x6b, 0xc9, 0x36, 0x2c, 0x66, 0x31, 0x24, 0x45, 0x87 }, + { 0x5e, 0xf9, 0x1d, 0x10, 0xb5, 0x79, 0x1f, 0x80, 0x85, 0x90, 0xc3, 0x7f, 0x2b, 0x73, 0xbf, 0x83, + 0x0b, 0x5d, 0x46, 0xae, 0x79, 0xef, 0x09, 0x71, 0x29, 0xfb, 0x83, 0xde, 0x1f, 0xe2, 0xdb, 0x1b, + 0xa2, 0x22, 0xee, 0x50, 0x21, 0x9d, 0x9c, 0x35, 0x14, 0x48, 0x13, 0xa5, 0xd1, 0x68, 0xf4, 0x61, + 0x1f, 0xd7, 0xe2, 0xd6, 0x42, 0x1c, 0xdc, 0x58, 0xec, 0x8b, 0x03, 0x6b, 0xdf, 0x64, 0x06, 0x30 }, + { 0xf9, 0xa6, 0x88, 0x74, 0x07, 0x19, 0x15, 0x38, 0xaf, 0xac, 0x07, 0x10, 0xe0, 0xd9, 0x22, 0xf3, + 0x78, 0xb0, 0xbf, 0x60, 0xa3, 0x0f, 0xea, 0x0f, 0xa8, 0x64, 0xa9, 0xa3, 0x82, 0xe1, 0x4c, 0x29, + 0x36, 0x22, 0x6d, 0x43, 0x9c, 0xde, 0x22, 0xbf, 0xc6, 0x85, 0xf7, 0xe9, 0xe0, 0x79, 0x80, 0xfe, + 0x9d, 0xd6, 0x24, 0xbd, 0x29, 0xa4, 0x8c, 0x35, 0x21, 0x87, 0x45, 0x7f, 0x88, 0xd9, 0x9a, 0x9d }, + { 0x49, 0x43, 0x19, 0x14, 0xcc, 0x4a, 0x11, 0x01, 0x05, 0xd1, 0x4e, 0x39, 0x6d, 0xb0, 0x22, 0x65, + 0x32, 0x6e, 0x67, 0x04, 0x50, 0x85, 0x53, 0x42, 0x90, 0x2c, 0xc0, 0x63, 0x2f, 0xbd, 0x15, 0x90, + 0x1b, 0x3f, 0x03, 0x90, 0x16, 0x7f, 0x7b, 0x49, 0x74, 0xd0, 0x3d, 0x81, 0x80, 0x1e, 0x9e, 0x2e, + 0xa9, 0x13, 0x6a, 0x10, 0x14, 0xc1, 0xfd, 0xf9, 0x25, 0x3a, 0x1d, 0x52, 0x93, 0x0a, 0x77, 0x03, + 0xa2, 0xdd, 0xce, 0x9f, 0x2a, 0x35, 0xc9, 0x93, 0x7c, 0xa2, 0x2c, 0xf6, 0x38, 0x73, 0xb3, 0xab, + 0x7f, 0x55, 0xb6, 0x62, 0xa2, 0x8d, 0x6a, 0x3e, 0x88, 0x04, 0x9b, 0xa2, 0x19, 0x64, 0x55, 0x01 }, + { 0x22, 0x03, 0x49, 0x58, 0x76, 0x3c, 0x85, 0x45, 0x5e, 0x73, 0x78, 0x8f, 0x65, 0xc9, 0x50, 0xf8, + 0xd7, 0x16, 0x92, 0xa4, 0xd1, 0x79, 0xce, 0xf3, 0x00, 0x34, 0x38, 0xb8, 0xcc, 0x96, 0x9f, 0xa6, + 0x87, 0x28, 0xcb, 0x19, 0x28, 0xad, 0x83, 0xb5, 0x09, 0x96, 0x54, 0xe8, 0x2a, 0xb9, 0x9b, 0xff, + 0x60, 0x85, 0x31, 0x28, 0x62, 0x36, 0xd2, 0x0e, 0xad, 0x2a, 0xe1, 0x84, 0x80, 0xeb, 0x6f, 0x00, + 0xa2, 0xdd, 0xce, 0x9f, 0x2a, 0x35, 0xc9, 0x93, 0x7c, 0xa2, 0x2c, 0xf6, 0x38, 0x73, 0xb3, 0xab, + 0x7f, 0x55, 0xb6, 0x62, 0xa2, 0x8d, 0x6a, 0x3e, 0x88, 0x04, 0x9b, 0xa2, 0x19, 0x64, 0x55, 0x01 } }, + { { 0xeb, 0x18, 0x95, 0x94, 0x5f, 0x15, 0x8c, 0xb8, 0x4d, 0x6e, 0x7d, 0xc0, 0x96, 0x6c, 0x52, 0xa2, + 0x5f, 0x43, 0x67, 0xc2, 0x3a, 0x10, 0x5b, 0xf1, 0x8f, 0x21, 0x89, 0x06, 0x77, 0xe9, 0xab, 0x2e, + 0xcd, 0x17, 0x9c, 0x9a, 0xd7, 0x89, 0x7e, 0x53, 0x58, 0x60, 0x9b, 0xce, 0x90, 0xd9, 0x13, 0x2d, + 0x78, 0xc4, 0x2c, 0x1c, 0x4c, 0xe8, 0x23, 0x70, 0xff, 0xa0, 0x42, 0x98, 0x25, 0x40, 0xd6, 0xd8 }, + { 0xb6, 0xfb, 0xdd, 0x5d, 0x35, 0xf2, 0x2b, 0x89, 0xda, 0x8e, 0x90, 0xee, 0x03, 0x4e, 0x75, 0xdb, + 0x4c, 0x45, 0xc8, 0x00, 0xde, 0x06, 0x27, 0xde, 0x44, 0xb5, 0x5b, 0xc7, 0x56, 0xc3, 0xf5, 0xbb, + 0xee, 0xa6, 0x21, 0xd4, 0xd9, 0xb9, 0x24, 0x9c, 0x4c, 0xbc, 0x23, 0xe5, 0xeb, 0x05, 0xb6, 0xd0, + 0xd0, 0xbf, 0x49, 0x95, 0x01, 0xb4, 0x97, 0xad, 0xb5, 0x71, 0x8d, 0x4b, 0x32, 0xd0, 0xdd, 0x1a }, + { 0xfd, 0x11, 0xd7, 0xe4, 0x46, 0xcd, 0xd8, 0x44, 0x89, 0x0a, 0xe7, 0x44, 0x59, 0xe9, 0xcf, 0x9f, + 0xd6, 0xf1, 0x74, 0x56, 0x04, 0x78, 0xfa, 0x29, 0x46, 0x8a, 0x8d, 0x1b, 0xbe, 0x41, 0x92, 0x1c, + 0x8d, 0x74, 0x01, 0x1b, 0xc1, 0xf8, 0x26, 0xf4, 0xc2, 0x68, 0xc3, 0x23, 0x8c, 0x68, 0x7c, 0x0a, + 0xad, 0xdd, 0x50, 0x10, 0xcf, 0xdb, 0x78, 0xc5, 0x79, 0x28, 0x37, 0x63, 0x92, 0x1a, 0x1d, 0xea }, + { 0xd2, 0x2a, 0xf0, 0x66, 0x15, 0x8b, 0xcb, 0x83, 0xcf, 0x34, 0xa1, 0x33, 0x6b, 0xd5, 0xa8, 0x98, + 0x3b, 0xd7, 0x09, 0x0d, 0x70, 0xa5, 0x8a, 0xc0, 0x73, 0xcf, 0xde, 0x59, 0xd5, 0x13, 0x41, 0xd2, + 0x43, 0x8b, 0xb4, 0xc3, 0x5b, 0x6f, 0xf1, 0xed, 0x47, 0x76, 0xe6, 0x5e, 0xb8, 0x2a, 0x7e, 0x20, + 0x91, 0xa0, 0x9d, 0xc1, 0xa2, 0x0a, 0x6d, 0x97, 0x7d, 0xeb, 0xe3, 0x64, 0x5f, 0x86, 0xff, 0x3e }, + { 0x45, 0xd8, 0xdc, 0xe4, 0x3a, 0x3a, 0x44, 0xdc, 0x7f, 0xa8, 0x92, 0x11, 0x1b, 0x4f, 0xfa, 0xcf, + 0x21, 0xff, 0xfb, 0x20, 0xb0, 0x02, 0x6d, 0x0e, 0x1c, 0xde, 0xe8, 0x51, 0xd8, 0x2c, 0x72, 0x0e, + 0xbf, 0xf6, 0x9a, 0xd3, 0xd3, 0xfe, 0xfa, 0x98, 0x4e, 0xc2, 0xf0, 0x16, 0xda, 0x39, 0x93, 0xc4, + 0xe0, 0x33, 0x9a, 0x43, 0xe8, 0x7a, 0xc5, 0x0f, 0x0b, 0xa4, 0x45, 0xf0, 0x5e, 0x7a, 0xa9, 0x42 }, + { 0xdb, 0x4e, 0x17, 0x76, 0x8b, 0x3c, 0x98, 0x7f, 0x58, 0x76, 0x97, 0xc9, 0x3f, 0x99, 0x01, 0x05, + 0x42, 0x7e, 0xfd, 0x83, 0x99, 0xaa, 0x19, 0xb5, 0x72, 0x4c, 0x69, 0xed, 0x6e, 0x21, 0x79, 0x6e, + 0x3b, 0x71, 0xe5, 0xab, 0x23, 0x84, 0xe7, 0xfe, 0x58, 0x2b, 0x0d, 0x1e, 0x75, 0x7c, 0x29, 0xb3, + 0x2d, 0x66, 0xc2, 0x45, 0x88, 0xac, 0x86, 0x29, 0xe4, 0xaa, 0x9e, 0x71, 0xa1, 0x88, 0xf9, 0x06, + 0xda, 0xa3, 0xdd, 0x7b, 0x6c, 0xd9, 0xc9, 0x73, 0xe9, 0x56, 0xd1, 0xee, 0x5b, 0xf9, 0xae, 0xc0, + 0x29, 0xbe, 0x20, 0x6c, 0xc7, 0xf9, 0xc5, 0x2d, 0x6d, 0xad, 0x8f, 0x49, 0xf8, 0x17, 0xdb, 0x7a }, + { 0xb8, 0xb7, 0xec, 0xeb, 0x3e, 0x40, 0x77, 0x6c, 0xab, 0x10, 0xfe, 0x9f, 0xd1, 0x40, 0xfe, 0xd2, + 0x88, 0x8e, 0xb0, 0x55, 0xae, 0x75, 0xb1, 0xcc, 0x9d, 0x6c, 0x11, 0x28, 0x95, 0x38, 0x9f, 0xb9, + 0x59, 0xe2, 0x29, 0xc3, 0xbc, 0x09, 0x16, 0x1f, 0x17, 0x9e, 0x15, 0x78, 0x09, 0x61, 0x07, 0x9e, + 0xad, 0x67, 0x98, 0xa9, 0x24, 0xff, 0xf9, 0x4b, 0xa2, 0x76, 0x09, 0xa0, 0xd7, 0x1b, 0xed, 0x05, + 0xda, 0xa3, 0xdd, 0x7b, 0x6c, 0xd9, 0xc9, 0x73, 0xe9, 0x56, 0xd1, 0xee, 0x5b, 0xf9, 0xae, 0xc0, + 0x29, 0xbe, 0x20, 0x6c, 0xc7, 0xf9, 0xc5, 0x2d, 0x6d, 0xad, 0x8f, 0x49, 0xf8, 0x17, 0xdb, 0x7a } }, + { { 0xc3, 0x92, 0x4d, 0x01, 0x9c, 0xea, 0x5a, 0x8d, 0xbd, 0x5c, 0x12, 0x58, 0x6d, 0x03, 0x26, 0xbf, + 0xa4, 0xdd, 0xf7, 0x26, 0xa4, 0x0d, 0x22, 0xe0, 0xbd, 0xcc, 0x6f, 0x30, 0x9e, 0xf9, 0x4c, 0x1f, + 0x03, 0x52, 0xab, 0x38, 0xe9, 0x9c, 0x08, 0x9c, 0x09, 0xe5, 0x87, 0x5c, 0x24, 0x1a, 0xe2, 0x75, + 0xcb, 0x18, 0x8a, 0x63, 0x50, 0xd1, 0x23, 0x45, 0x49, 0x93, 0x40, 0x2c, 0x09, 0xd4, 0xac, 0x39 }, + { 0xd4, 0xe7, 0xb7, 0x05, 0xfd, 0xd6, 0xf3, 0x57, 0xfb, 0xc2, 0x2f, 0x2c, 0x71, 0x80, 0xf5, 0xc3, + 0xa6, 0x0a, 0x23, 0x9d, 0x1d, 0xa8, 0x68, 0x10, 0x8a, 0xfa, 0x68, 0x9d, 0x2b, 0xcf, 0x96, 0xa9, + 0xe6, 0x0e, 0x07, 0x32, 0x23, 0x09, 0x87, 0x16, 0xc5, 0xbb, 0x76, 0x22, 0xfc, 0xb4, 0x59, 0x6d, + 0x67, 0xfd, 0x29, 0x51, 0x95, 0x4c, 0xe2, 0x8c, 0x18, 0xab, 0xda, 0x84, 0xc3, 0x62, 0x80, 0x14 }, + { 0xc9, 0xa1, 0xfe, 0xc3, 0x48, 0x0d, 0xee, 0x54, 0x44, 0xff, 0x9c, 0x46, 0x04, 0x0e, 0x74, 0xda, + 0xa4, 0x6a, 0x56, 0x02, 0x5f, 0x76, 0x0e, 0xb5, 0xc1, 0xc9, 0xe9, 0xb2, 0x6e, 0x07, 0x49, 0x0c, + 0xf7, 0x4b, 0xee, 0xd6, 0x0a, 0xad, 0x94, 0x03, 0x58, 0x2d, 0x60, 0x95, 0xf8, 0x16, 0x7b, 0x49, + 0x0b, 0x01, 0x66, 0x3e, 0x17, 0x01, 0xe5, 0x54, 0x7d, 0xd7, 0xbb, 0x10, 0xd1, 0xad, 0xad, 0x79 }, + { 0xb2, 0xd8, 0x10, 0x29, 0xeb, 0xb8, 0x4e, 0x2b, 0x39, 0x85, 0x5c, 0xb3, 0xdc, 0xf5, 0x87, 0xca, + 0xca, 0x9c, 0x7a, 0x8c, 0x2b, 0x08, 0xe8, 0x25, 0xe2, 0xcf, 0x70, 0xe2, 0xe6, 0xfb, 0xdb, 0x0c, + 0xc3, 0x0d, 0x71, 0x11, 0x83, 0x65, 0xf2, 0x71, 0x08, 0x1b, 0x32, 0x6e, 0x6c, 0x51, 0x50, 0xf1, + 0xf6, 0x4b, 0x54, 0x63, 0x16, 0x7f, 0xfd, 0x80, 0x05, 0x61, 0x63, 0xf1, 0x80, 0x6a, 0x0b, 0xfd }, + { 0xa7, 0x4b, 0x75, 0x38, 0x90, 0x64, 0x96, 0x7b, 0xda, 0x5e, 0x08, 0x9b, 0x80, 0xc4, 0x72, 0x3f, + 0x73, 0xb2, 0xdb, 0xd3, 0x4a, 0xed, 0xa4, 0xdc, 0x5c, 0x79, 0xe5, 0x0f, 0x7a, 0xd3, 0x0c, 0xac, + 0xf9, 0x99, 0x5c, 0x1a, 0x0f, 0xb3, 0x1a, 0x0f, 0x5c, 0xc3, 0x9e, 0x1a, 0x2b, 0xfa, 0xc3, 0xf0, + 0x40, 0xe5, 0x5f, 0x36, 0xd2, 0x98, 0x31, 0xa1, 0xaf, 0x18, 0x5f, 0xae, 0x92, 0xf3, 0x9e, 0xc0 }, + { 0xf9, 0xbf, 0x52, 0xe6, 0xd3, 0xe1, 0x5d, 0xd3, 0x30, 0xf3, 0xa1, 0x0c, 0xc8, 0x5a, 0x97, 0x55, + 0xab, 0x67, 0x67, 0xd0, 0x00, 0x62, 0x7b, 0x80, 0x70, 0xbf, 0x24, 0xd0, 0x09, 0x8b, 0x07, 0x77, + 0xeb, 0x3e, 0xf0, 0x5d, 0xdf, 0x7b, 0xa9, 0x7d, 0xa4, 0x6a, 0x0d, 0xf1, 0xac, 0x83, 0x7d, 0x64, + 0xb5, 0xf4, 0xc6, 0xc4, 0x12, 0x0c, 0x55, 0x9f, 0x67, 0xbb, 0xd5, 0xe3, 0xd3, 0xdb, 0x17, 0x0f, + 0x90, 0x2f, 0x8f, 0xc9, 0xfd, 0x4e, 0x6c, 0x8b, 0xe6, 0x99, 0xfa, 0xda, 0x8f, 0x1f, 0xe6, 0xc3, + 0xeb, 0xd8, 0x14, 0x20, 0xcc, 0x3c, 0x1c, 0x23, 0x77, 0x28, 0x9b, 0x22, 0x9a, 0x5a, 0x0c, 0x43 }, + { 0xa2, 0x78, 0x37, 0xc9, 0x63, 0xe1, 0x31, 0x36, 0xc2, 0x58, 0xac, 0xca, 0xbb, 0xa2, 0x84, 0xaa, + 0xb3, 0x82, 0xe2, 0x19, 0xb7, 0x14, 0x96, 0x27, 0x77, 0xfa, 0xa1, 0x02, 0xaa, 0xff, 0x55, 0x82, + 0xba, 0xc0, 0x38, 0x1a, 0x69, 0x35, 0x48, 0x87, 0xc2, 0xeb, 0x48, 0x08, 0xea, 0xc5, 0x6b, 0xfc, + 0x84, 0x60, 0x4e, 0xce, 0xd7, 0xd2, 0x86, 0x8b, 0x76, 0xf3, 0x46, 0xe1, 0x87, 0x1f, 0xff, 0x09, + 0x90, 0x2f, 0x8f, 0xc9, 0xfd, 0x4e, 0x6c, 0x8b, 0xe6, 0x99, 0xfa, 0xda, 0x8f, 0x1f, 0xe6, 0xc3, + 0xeb, 0xd8, 0x14, 0x20, 0xcc, 0x3c, 0x1c, 0x23, 0x77, 0x28, 0x9b, 0x22, 0x9a, 0x5a, 0x0c, 0x43 } }, + { { 0x0e, 0xa6, 0x0c, 0xef, 0x12, 0xd6, 0x7d, 0x71, 0xd4, 0x88, 0x73, 0x86, 0x9a, 0x88, 0x8f, 0x5b, + 0xd1, 0xb6, 0x12, 0xc4, 0x93, 0x8b, 0x5f, 0xee, 0xdd, 0x9c, 0x2a, 0x7f, 0x4d, 0xfd, 0xba, 0x00, + 0x09, 0x45, 0x77, 0xd2, 0xcf, 0xcd, 0x3a, 0x6f, 0x27, 0x44, 0xe2, 0x55, 0x3e, 0x79, 0x88, 0x4d, + 0x5f, 0x38, 0x34, 0xe8, 0xe7, 0xc6, 0x3a, 0xde, 0xef, 0x99, 0x15, 0xea, 0x88, 0x79, 0xd7, 0xca }, + { 0xa0, 0x9a, 0x0a, 0x3a, 0x42, 0x35, 0x54, 0x78, 0xb9, 0x82, 0x52, 0xb4, 0xc8, 0x5c, 0x4a, 0x03, + 0xa1, 0xb9, 0x27, 0xcc, 0x99, 0xec, 0x03, 0xdf, 0xdd, 0x6e, 0xde, 0xef, 0x8f, 0x7f, 0xdc, 0x5a, + 0xc3, 0xcb, 0x0e, 0xa2, 0x7e, 0x93, 0xe6, 0xdd, 0xbd, 0xf1, 0x1b, 0x03, 0x29, 0x63, 0x72, 0x11, + 0x72, 0x3d, 0x24, 0x6f, 0xdf, 0x8e, 0xed, 0xa4, 0xe2, 0x2a, 0x4c, 0x00, 0xe2, 0xc4, 0x55, 0x1b }, + { 0xb2, 0xf1, 0xff, 0xf6, 0x3a, 0x26, 0xe1, 0x74, 0x52, 0xba, 0xee, 0x28, 0xb6, 0x56, 0x90, 0x59, + 0xde, 0x92, 0x5f, 0x84, 0xd1, 0x87, 0xe2, 0x64, 0xce, 0xdc, 0x94, 0x3c, 0xb4, 0xf8, 0x01, 0x0a, + 0x86, 0x2f, 0xfe, 0x79, 0x03, 0x72, 0xfc, 0x26, 0x21, 0xc3, 0x1e, 0xec, 0x63, 0x29, 0x64, 0xcb, + 0x5f, 0xcc, 0xb6, 0x78, 0xf7, 0xc8, 0xd1, 0xf8, 0x5c, 0xc4, 0x4b, 0xc0, 0xc3, 0x75, 0x3e, 0x46 }, + { 0x03, 0x4b, 0xb9, 0xd1, 0x50, 0xa3, 0x79, 0xbe, 0x74, 0xa3, 0xb5, 0xd8, 0x28, 0x1b, 0x6d, 0x72, + 0x68, 0x0a, 0x9b, 0x19, 0xc9, 0x13, 0xc4, 0x04, 0x94, 0x0a, 0xcb, 0x72, 0xff, 0x7d, 0xb6, 0x9a, + 0x1c, 0xfd, 0xe4, 0xa3, 0x75, 0x13, 0x57, 0x36, 0xfe, 0x4a, 0xf6, 0xbc, 0xca, 0xd9, 0x34, 0x9b, + 0xef, 0x90, 0x02, 0xd9, 0xbd, 0xdd, 0x6f, 0x22, 0x54, 0x36, 0xb2, 0x3f, 0x22, 0x65, 0xef, 0xe7 }, + { 0x04, 0xd4, 0x43, 0xe8, 0x8c, 0xc4, 0xfb, 0xe5, 0x55, 0xd0, 0xa4, 0xea, 0x20, 0xf8, 0xe1, 0x8f, + 0xc2, 0xbc, 0x1f, 0x55, 0xf1, 0x8d, 0xda, 0xc0, 0x85, 0xa4, 0xef, 0x36, 0x97, 0x22, 0x8b, 0x8e, + 0x77, 0x4c, 0x1a, 0xa4, 0xa0, 0x6f, 0xe1, 0xdc, 0x32, 0x47, 0xc4, 0x3a, 0xd8, 0x8a, 0xbd, 0x19, + 0x30, 0x1c, 0x96, 0x7a, 0xb2, 0x23, 0x7c, 0x16, 0x03, 0xa7, 0x4f, 0xfd, 0xa6, 0x50, 0xd9, 0xf7 }, + { 0xdf, 0xc2, 0x59, 0xd2, 0xa9, 0x9b, 0x1e, 0xca, 0xf0, 0x39, 0x2f, 0xf8, 0xc2, 0xf3, 0x91, 0x55, + 0x1b, 0xba, 0x81, 0x3a, 0x67, 0x1a, 0xd4, 0xf4, 0xb0, 0x9f, 0xb6, 0x18, 0x38, 0x65, 0x3e, 0x67, + 0xa0, 0x37, 0xc2, 0x9a, 0xc7, 0xee, 0x72, 0x8e, 0x13, 0x64, 0xd1, 0x0a, 0xda, 0xbd, 0x8d, 0xa4, + 0x28, 0x55, 0x3a, 0x2c, 0x78, 0x41, 0xc6, 0xfc, 0x1c, 0x0f, 0xf8, 0xd7, 0x5f, 0xe6, 0xde, 0x0b, + 0xd5, 0xc0, 0xaa, 0x2c, 0x5c, 0xac, 0x46, 0xeb, 0xa4, 0x35, 0x2a, 0xab, 0x00, 0x2e, 0xc0, 0x8b, + 0x42, 0x65, 0x2f, 0x2f, 0x13, 0x84, 0x60, 0x15, 0xa3, 0x69, 0xee, 0xab, 0x0e, 0x50, 0xbf, 0x5f }, + { 0xc1, 0xb0, 0xac, 0x4c, 0xfa, 0x62, 0x52, 0x22, 0xae, 0x8c, 0x94, 0x38, 0xd9, 0x6e, 0x10, 0x94, + 0xe7, 0xaa, 0xc0, 0x92, 0x93, 0x06, 0x55, 0xf9, 0x2e, 0xd9, 0x10, 0x4d, 0xcb, 0x82, 0x19, 0x1f, + 0x27, 0x16, 0x81, 0xdd, 0xea, 0x7a, 0xa8, 0xce, 0x5a, 0xdd, 0x37, 0x77, 0x24, 0x57, 0xfb, 0x40, + 0x3d, 0x1b, 0x48, 0x88, 0xda, 0xce, 0xe8, 0xd2, 0xed, 0xe0, 0x6e, 0x29, 0xeb, 0xdb, 0x95, 0x09, + 0xd5, 0xc0, 0xaa, 0x2c, 0x5c, 0xac, 0x46, 0xeb, 0xa4, 0x35, 0x2a, 0xab, 0x00, 0x2e, 0xc0, 0x8b, + 0x42, 0x65, 0x2f, 0x2f, 0x13, 0x84, 0x60, 0x15, 0xa3, 0x69, 0xee, 0xab, 0x0e, 0x50, 0xbf, 0x5f } }, + { { 0x3a, 0x79, 0x39, 0x60, 0xe9, 0x93, 0xad, 0x78, 0xf9, 0x0b, 0x99, 0x64, 0x71, 0x76, 0xad, 0xdc, + 0x63, 0xa3, 0x38, 0xbf, 0x0a, 0x36, 0x22, 0xcf, 0x4f, 0x84, 0x3e, 0x34, 0xaf, 0x0b, 0xd4, 0x5c, + 0xc0, 0xa4, 0x01, 0x7c, 0x07, 0xc3, 0xb4, 0xcb, 0xdb, 0x39, 0xdd, 0x39, 0xc7, 0x5c, 0xbd, 0xcf, + 0x61, 0x8b, 0x72, 0x74, 0xd6, 0x85, 0xdc, 0x5c, 0x08, 0x93, 0x6d, 0xe6, 0xf1, 0xeb, 0xb9, 0x7c }, + { 0x71, 0x12, 0x20, 0xbb, 0x37, 0xa6, 0xd8, 0x71, 0xf7, 0x58, 0xaa, 0xbd, 0x30, 0xfb, 0xac, 0x94, + 0x62, 0x45, 0xf0, 0x1a, 0xc3, 0x4a, 0x07, 0x78, 0x6d, 0x17, 0xf5, 0x8d, 0x69, 0x3d, 0x2e, 0x15, + 0x96, 0x48, 0x1a, 0xb0, 0x7e, 0xdd, 0xf5, 0x2d, 0xe1, 0x56, 0xfc, 0xe9, 0x26, 0x91, 0x51, 0xfe, + 0x5e, 0x2a, 0xdc, 0x23, 0x89, 0x09, 0x14, 0xe6, 0x17, 0xa9, 0x14, 0x8c, 0x8c, 0xe8, 0xe3, 0x71 }, + { 0xe4, 0xd0, 0xa7, 0x5a, 0xce, 0x93, 0x1d, 0x55, 0xa2, 0x3d, 0xdd, 0x7e, 0x10, 0x66, 0x6d, 0xc6, + 0x5c, 0x87, 0x9f, 0x7a, 0x52, 0x5e, 0x76, 0x3f, 0x09, 0x9e, 0xe5, 0x8e, 0x60, 0x39, 0x5e, 0x3c, + 0x28, 0x31, 0xa4, 0x12, 0x39, 0xfd, 0xba, 0xda, 0xc8, 0x59, 0xdd, 0x5b, 0x26, 0x78, 0x8f, 0x33, + 0xd2, 0xc8, 0x22, 0x77, 0x49, 0xcf, 0x34, 0x61, 0xbe, 0x7a, 0xa6, 0x31, 0xbe, 0xe5, 0xab, 0xc2 }, + { 0x60, 0xf5, 0x52, 0xbd, 0xb1, 0x9e, 0x06, 0xa3, 0x94, 0xad, 0xe0, 0x82, 0x33, 0x7c, 0x41, 0x17, + 0x5b, 0x8a, 0xbc, 0x7c, 0xce, 0xd1, 0x7e, 0xfd, 0x39, 0x17, 0xfd, 0x90, 0x5a, 0x53, 0x89, 0x27, + 0x9f, 0x27, 0x7a, 0x08, 0xb2, 0x66, 0xda, 0xb5, 0xbf, 0x3b, 0x80, 0xe2, 0x1a, 0x30, 0x80, 0x45, + 0x13, 0xf3, 0x4b, 0x0c, 0x4a, 0xe9, 0x0a, 0x6e, 0xf2, 0x3e, 0xa3, 0x70, 0x3d, 0x89, 0xd3, 0xb2 }, + { 0x23, 0x41, 0x08, 0x8d, 0xa8, 0x0b, 0x6a, 0xe0, 0x65, 0xb1, 0x42, 0x50, 0x49, 0xdd, 0xd3, 0xe8, + 0x89, 0x13, 0x7a, 0x04, 0xf0, 0xd6, 0x2f, 0x6e, 0x73, 0xcd, 0xdc, 0x10, 0xbb, 0x02, 0x6b, 0xa2, + 0x25, 0x58, 0xa3, 0x08, 0x37, 0x7c, 0x8b, 0x1f, 0x4a, 0x81, 0x38, 0x88, 0xbd, 0xf4, 0x4f, 0x24, + 0xe8, 0xd6, 0x9f, 0x2f, 0x13, 0xeb, 0x79, 0x60, 0x80, 0x90, 0x52, 0x6b, 0x8e, 0xed, 0xcb, 0x77 }, + { 0x5b, 0x88, 0x63, 0xaf, 0xf9, 0xe2, 0x44, 0x23, 0xc8, 0x02, 0xe0, 0x22, 0x15, 0x3d, 0x2a, 0xb7, + 0x40, 0x76, 0xe8, 0x95, 0xfd, 0xa9, 0xe3, 0x85, 0x94, 0xa3, 0xbb, 0xce, 0x61, 0x19, 0x0d, 0xe2, + 0x95, 0xdf, 0x81, 0x11, 0x53, 0x77, 0xcd, 0xf2, 0xd8, 0x4f, 0xbf, 0x19, 0x6a, 0x3d, 0x4b, 0xda, + 0xa4, 0x56, 0xa4, 0xcd, 0x9d, 0x4f, 0x52, 0x53, 0x7d, 0xd8, 0xac, 0xe0, 0xfb, 0x9a, 0x71, 0x0c, + 0x59, 0xf9, 0x0b, 0x03, 0xf1, 0x7b, 0xaf, 0x33, 0xc3, 0xe5, 0x1e, 0x8d, 0x4f, 0xbe, 0x21, 0xed, + 0x6b, 0x15, 0xdd, 0xd2, 0xeb, 0x7c, 0xe4, 0x59, 0x6c, 0xf9, 0x91, 0xc1, 0x3a, 0x3a, 0xb6, 0x2b }, + { 0x5e, 0x54, 0xe5, 0x1b, 0x3d, 0x2c, 0x00, 0x80, 0xdd, 0xe4, 0x10, 0x50, 0x98, 0xb6, 0x0e, 0x3a, + 0xf7, 0xde, 0x67, 0x2c, 0x8e, 0x7b, 0xb4, 0x73, 0x0b, 0xc7, 0x12, 0xb0, 0x66, 0x6b, 0x3b, 0x99, + 0xd9, 0x33, 0x78, 0x5f, 0x45, 0xe5, 0xec, 0x15, 0x02, 0xfa, 0x8b, 0x86, 0xfd, 0xe0, 0xb7, 0x84, + 0x72, 0xf2, 0x68, 0x5c, 0xd6, 0x2e, 0x37, 0xe9, 0x49, 0x32, 0x2f, 0xcd, 0xcd, 0x1e, 0x99, 0x0f, + 0x59, 0xf9, 0x0b, 0x03, 0xf1, 0x7b, 0xaf, 0x33, 0xc3, 0xe5, 0x1e, 0x8d, 0x4f, 0xbe, 0x21, 0xed, + 0x6b, 0x15, 0xdd, 0xd2, 0xeb, 0x7c, 0xe4, 0x59, 0x6c, 0xf9, 0x91, 0xc1, 0x3a, 0x3a, 0xb6, 0x2b } }, + { { 0xfc, 0xb9, 0x4e, 0x4e, 0x11, 0xfe, 0xe1, 0xc5, 0xc7, 0x49, 0x54, 0xd2, 0x2f, 0x13, 0x34, 0x7c, + 0x91, 0x7d, 0x98, 0x43, 0xe4, 0xb7, 0x48, 0xea, 0xe8, 0x26, 0xcb, 0x26, 0x1f, 0xe4, 0x99, 0x10, + 0xb9, 0x34, 0xc2, 0xac, 0xa3, 0x2c, 0xbd, 0x9e, 0x80, 0xd4, 0x12, 0x3b, 0xb3, 0xf0, 0x01, 0xae, + 0x91, 0x9f, 0xba, 0x77, 0x32, 0x4d, 0x9d, 0xac, 0x1f, 0x8d, 0xad, 0xa7, 0x46, 0x44, 0x85, 0xfb }, + { 0x65, 0x05, 0x0b, 0xd2, 0x41, 0xd3, 0x58, 0x2a, 0x14, 0xbc, 0x7b, 0x15, 0x4a, 0x6a, 0x6a, 0x18, + 0x71, 0x09, 0x25, 0x33, 0xac, 0x73, 0x53, 0xab, 0xd9, 0x0d, 0x8d, 0xdf, 0x95, 0x59, 0x7e, 0x02, + 0x4c, 0x03, 0x11, 0x5c, 0xdc, 0x80, 0x19, 0xd5, 0x13, 0x66, 0x7f, 0xf7, 0xd7, 0x23, 0x18, 0x40, + 0x84, 0x16, 0x6b, 0x52, 0x82, 0x96, 0x05, 0x1b, 0xfa, 0xcb, 0x4b, 0x77, 0x00, 0x12, 0xa0, 0x28 }, + { 0x13, 0xe0, 0x16, 0x1e, 0x24, 0x24, 0xe9, 0xde, 0x9c, 0x86, 0xa9, 0xcf, 0x02, 0x96, 0xdf, 0x8c, + 0x64, 0xcb, 0x3d, 0x7d, 0x8a, 0x2a, 0x73, 0x18, 0x20, 0xc8, 0xb0, 0xac, 0x10, 0xa0, 0x52, 0x0c, + 0x6c, 0x17, 0xd9, 0xbd, 0x3c, 0x3e, 0xe5, 0x0c, 0x4a, 0xdb, 0x59, 0xcc, 0x59, 0x15, 0x08, 0x1e, + 0xfe, 0xaa, 0xe3, 0xd6, 0xa1, 0x37, 0xd6, 0xd5, 0x6d, 0x8e, 0xcd, 0x57, 0xa9, 0x81, 0xb3, 0x43 }, + { 0x46, 0x28, 0x2b, 0xa0, 0xe5, 0xe3, 0xf0, 0x72, 0xa7, 0xbc, 0x8d, 0xec, 0x45, 0x31, 0x6e, 0xdb, + 0xb2, 0x4b, 0x20, 0xbf, 0x64, 0x74, 0x26, 0x70, 0x9b, 0xd6, 0xd3, 0x7f, 0x9f, 0xc1, 0x59, 0x03, + 0x2d, 0xda, 0x6f, 0xaa, 0x7c, 0x92, 0xc6, 0xe0, 0xe8, 0xaa, 0x1e, 0x26, 0xf0, 0x1e, 0xcc, 0xef, + 0x6d, 0x87, 0x04, 0x3c, 0xed, 0x52, 0x15, 0xb3, 0x9f, 0x01, 0x4e, 0xe3, 0x3c, 0xb6, 0xbb, 0xac }, + { 0x86, 0x1a, 0x25, 0x8e, 0x41, 0x85, 0xf9, 0xba, 0x98, 0x15, 0xb1, 0xec, 0x50, 0xb4, 0xd0, 0xab, + 0x55, 0x54, 0xbb, 0x3b, 0x61, 0xfc, 0x54, 0xf3, 0x09, 0xea, 0xaa, 0x6e, 0xbf, 0x03, 0xc3, 0x58, + 0x1d, 0x24, 0xb5, 0xd5, 0x45, 0x5a, 0x7a, 0x14, 0xc3, 0x6a, 0xa9, 0xd8, 0x6f, 0x41, 0xc3, 0xb4, + 0x9a, 0x05, 0x71, 0xbc, 0x23, 0x67, 0xc2, 0xa8, 0xf5, 0x7b, 0x69, 0xa5, 0xe1, 0x7a, 0x35, 0x1d }, + { 0x3b, 0xf5, 0xa8, 0xc0, 0x2a, 0x7d, 0x85, 0x88, 0xd4, 0xf4, 0x26, 0xd3, 0xf4, 0xe3, 0x52, 0x35, + 0x37, 0x06, 0x1e, 0x71, 0xc2, 0x3b, 0x7b, 0xeb, 0xf0, 0x07, 0x30, 0x6b, 0x37, 0x31, 0xb9, 0x27, + 0xd8, 0x0b, 0x17, 0xae, 0xff, 0xd4, 0x7c, 0x59, 0xd7, 0x2d, 0xea, 0xcb, 0x92, 0x2f, 0x93, 0xc7, + 0xd7, 0xc3, 0xaf, 0x75, 0x73, 0x6a, 0x3f, 0x89, 0xe5, 0x13, 0x0c, 0x28, 0x47, 0xf4, 0xa4, 0x07, + 0xfb, 0xd9, 0x77, 0xb4, 0x1e, 0xb2, 0x70, 0xca, 0x85, 0x22, 0x58, 0xc6, 0x0b, 0x19, 0xc2, 0xa5, + 0xba, 0xc3, 0xc9, 0xb6, 0x4a, 0xdb, 0x7d, 0x4d, 0x66, 0xde, 0xeb, 0x8c, 0x1a, 0x23, 0xb8, 0x4c }, + { 0x8c, 0x57, 0x0e, 0x9f, 0x0a, 0xb2, 0xf4, 0x07, 0xdd, 0x7b, 0x46, 0xf8, 0xa0, 0xb1, 0x33, 0x4c, + 0x2b, 0x1e, 0x1a, 0xe0, 0x28, 0x17, 0x14, 0xba, 0x14, 0x06, 0x40, 0x1f, 0x30, 0x0a, 0x19, 0xcd, + 0xe7, 0xca, 0xfb, 0xdb, 0xb9, 0x76, 0xf8, 0x8a, 0x81, 0x3d, 0x03, 0x86, 0x7e, 0x66, 0x75, 0x1d, + 0xec, 0xff, 0x6b, 0xa7, 0xea, 0x4c, 0x8c, 0x60, 0xd2, 0x1f, 0x72, 0x11, 0x4c, 0x5d, 0xeb, 0x01, + 0xfb, 0xd9, 0x77, 0xb4, 0x1e, 0xb2, 0x70, 0xca, 0x85, 0x22, 0x58, 0xc6, 0x0b, 0x19, 0xc2, 0xa5, + 0xba, 0xc3, 0xc9, 0xb6, 0x4a, 0xdb, 0x7d, 0x4d, 0x66, 0xde, 0xeb, 0x8c, 0x1a, 0x23, 0xb8, 0x4c } }, + { { 0x05, 0x64, 0x16, 0x53, 0xbb, 0xb2, 0x6e, 0x81, 0xfc, 0xe6, 0xec, 0xc8, 0x0c, 0xc1, 0x75, 0x59, + 0x23, 0xe2, 0x4b, 0xd8, 0x6a, 0x70, 0x34, 0x50, 0x37, 0xc6, 0xc2, 0xbd, 0x27, 0xfd, 0xad, 0x4c, + 0xee, 0xe4, 0xf7, 0xfc, 0x91, 0x05, 0x48, 0x3c, 0xd4, 0x09, 0x78, 0x00, 0xce, 0x15, 0x37, 0xdc, + 0xe7, 0xce, 0x48, 0x09, 0x3e, 0x7f, 0x01, 0x9b, 0x03, 0xc8, 0x2f, 0x9b, 0xe6, 0x42, 0xe1, 0x71 }, + { 0x64, 0xbf, 0x63, 0x91, 0xe5, 0x3e, 0x90, 0x89, 0x96, 0xea, 0x59, 0x51, 0x60, 0x7b, 0x5f, 0xfe, + 0x0f, 0x76, 0x86, 0x19, 0x45, 0x82, 0xd9, 0x5e, 0x1a, 0xd1, 0xf6, 0x04, 0xc6, 0xaa, 0x71, 0xda, + 0x80, 0xed, 0x75, 0x51, 0xc8, 0x9a, 0x27, 0x09, 0xc3, 0x50, 0xe4, 0x14, 0xa1, 0xc3, 0xf8, 0x3a, + 0x6c, 0x84, 0xff, 0x87, 0xd5, 0xf0, 0xb0, 0x3c, 0x5a, 0x57, 0x14, 0x90, 0xc7, 0x31, 0xf8, 0x47 }, + { 0x88, 0x7d, 0xcc, 0x81, 0x2b, 0xbb, 0x7e, 0x96, 0xbe, 0x78, 0xe1, 0xb1, 0xf2, 0xed, 0x6f, 0xd8, + 0xff, 0xbd, 0x7f, 0x8e, 0xe5, 0xeb, 0x7f, 0x7b, 0xca, 0xaf, 0x9b, 0x08, 0x1a, 0x77, 0x69, 0x1d, + 0xc2, 0xa4, 0x7c, 0x4d, 0xa6, 0x74, 0x8e, 0x33, 0x24, 0xff, 0x43, 0xe1, 0x8c, 0x59, 0xae, 0x5f, + 0x95, 0xa4, 0x35, 0x9e, 0x61, 0xb8, 0xcc, 0x4c, 0x87, 0xb9, 0x76, 0x53, 0x20, 0xa3, 0xf3, 0xf5 }, + { 0x13, 0x2a, 0xcc, 0x07, 0xb1, 0x5f, 0xc7, 0xf1, 0x08, 0x0e, 0x7d, 0x7e, 0x26, 0x56, 0xd8, 0x16, + 0x9c, 0xae, 0xac, 0xc4, 0xf5, 0x9c, 0x15, 0x67, 0xae, 0xc4, 0xcc, 0x3f, 0xc0, 0xaf, 0x53, 0x28, + 0x1f, 0x65, 0x14, 0xe5, 0x7f, 0x0c, 0xf5, 0x7a, 0xe3, 0x93, 0xc1, 0xa3, 0xd1, 0x4a, 0x09, 0x7d, + 0x24, 0xab, 0x22, 0xc4, 0xc4, 0xce, 0x85, 0x37, 0x86, 0xa8, 0x9c, 0x39, 0x33, 0xba, 0x1b, 0x83 }, + { 0x6d, 0x3e, 0x92, 0x5a, 0xa8, 0xfa, 0xe6, 0x71, 0x98, 0xa8, 0x82, 0x38, 0xcc, 0xed, 0xd6, 0x92, + 0x7e, 0x3e, 0xcb, 0xb2, 0x82, 0x92, 0x7a, 0x56, 0x9e, 0xd6, 0x29, 0x45, 0x42, 0x04, 0x76, 0x82, + 0xa5, 0xfc, 0xd9, 0x0c, 0x12, 0x4c, 0x98, 0x04, 0x2a, 0x3a, 0x98, 0x01, 0xb8, 0x62, 0xe8, 0xe6, + 0x7c, 0x51, 0xe3, 0x7d, 0x97, 0xf5, 0x45, 0xb4, 0x13, 0xdf, 0x15, 0x68, 0xc3, 0x00, 0x75, 0x40 }, + { 0x7e, 0x89, 0x3d, 0x7c, 0x78, 0x36, 0x3c, 0x85, 0xda, 0xb6, 0x9b, 0x6d, 0xbc, 0x52, 0x7d, 0xc6, + 0xaa, 0xfd, 0x90, 0x62, 0xe4, 0xc4, 0x1a, 0x5a, 0x2e, 0xa1, 0x57, 0xd7, 0xda, 0x57, 0xf4, 0x58, + 0xc5, 0x23, 0x61, 0x21, 0xe1, 0x93, 0xfa, 0x06, 0x22, 0xed, 0x41, 0x66, 0x24, 0x47, 0xb9, 0xed, + 0xc8, 0x84, 0x25, 0x28, 0x39, 0xec, 0xfb, 0x29, 0xa1, 0xcd, 0xe1, 0x9d, 0x02, 0x48, 0x6f, 0x0a, + 0xe2, 0x9f, 0x98, 0xfd, 0x3d, 0x18, 0xa1, 0x24, 0x9c, 0xc6, 0x75, 0xb8, 0x99, 0x76, 0x2a, 0xa4, + 0x9e, 0xb1, 0x97, 0x2d, 0x1c, 0x99, 0x65, 0x5f, 0x1f, 0xda, 0x14, 0x4f, 0x10, 0x49, 0xf1, 0x7a }, + { 0x2c, 0xec, 0x27, 0x63, 0xd2, 0x77, 0x14, 0x2d, 0x01, 0x18, 0x10, 0xe0, 0x23, 0x1b, 0xa2, 0x25, + 0x61, 0xd4, 0x52, 0xd9, 0x90, 0xde, 0x97, 0x7e, 0xb8, 0xfa, 0x38, 0x25, 0xf2, 0x91, 0x07, 0x3e, + 0xc4, 0xa9, 0x3e, 0xb5, 0x67, 0x02, 0x28, 0x94, 0x5c, 0x34, 0xa1, 0x0a, 0x5c, 0x54, 0x53, 0xd9, + 0xb4, 0xc4, 0x5a, 0x8e, 0x57, 0x18, 0xc3, 0x35, 0xea, 0x47, 0x75, 0xe0, 0x44, 0x01, 0x71, 0x09, + 0xe2, 0x9f, 0x98, 0xfd, 0x3d, 0x18, 0xa1, 0x24, 0x9c, 0xc6, 0x75, 0xb8, 0x99, 0x76, 0x2a, 0xa4, + 0x9e, 0xb1, 0x97, 0x2d, 0x1c, 0x99, 0x65, 0x5f, 0x1f, 0xda, 0x14, 0x4f, 0x10, 0x49, 0xf1, 0x7a } }, + { { 0x41, 0x10, 0xd9, 0x7f, 0xb8, 0x83, 0x9e, 0x42, 0x43, 0x7a, 0xb0, 0x6d, 0xa6, 0xcf, 0xa5, 0x7a, + 0x50, 0x93, 0x2d, 0x13, 0x94, 0x37, 0xa8, 0x92, 0x26, 0x1f, 0xad, 0xe0, 0x25, 0x19, 0x91, 0x62, + 0x28, 0xfb, 0x18, 0xbf, 0x89, 0xb0, 0x42, 0x80, 0x14, 0xcd, 0xd2, 0x72, 0x84, 0x1c, 0xfd, 0xe5, + 0xc3, 0x71, 0x3c, 0x3f, 0x12, 0x5e, 0xdd, 0x53, 0x39, 0xf6, 0x4b, 0x9f, 0xb3, 0x5c, 0xe3, 0x15 }, + { 0xd0, 0xc7, 0x18, 0x4d, 0x68, 0x9f, 0xdd, 0xec, 0x81, 0xf8, 0xc6, 0x0e, 0x83, 0x43, 0x23, 0x3d, + 0xfc, 0xf3, 0x66, 0x55, 0xa8, 0x65, 0x8b, 0xd7, 0x9b, 0x3c, 0x74, 0x23, 0xcd, 0xae, 0x60, 0xe7, + 0x61, 0xed, 0x2c, 0x7e, 0xe7, 0xa7, 0x63, 0x7d, 0x72, 0x47, 0x6a, 0x33, 0x1c, 0xaa, 0x81, 0xba, + 0x6f, 0xd4, 0x00, 0xe7, 0xa9, 0x58, 0xb2, 0xad, 0xee, 0x3f, 0x9c, 0x70, 0xff, 0x2f, 0x13, 0x6f }, + { 0x56, 0x7b, 0x19, 0x66, 0x42, 0x9a, 0x99, 0x51, 0x23, 0x4f, 0xb6, 0xe7, 0xcf, 0x98, 0xff, 0x20, + 0x5a, 0xc3, 0x0e, 0x36, 0xc9, 0xc6, 0x20, 0x25, 0x0c, 0x56, 0x98, 0xfb, 0xbd, 0xd6, 0x66, 0x4f, + 0x6f, 0x94, 0x85, 0x8a, 0x35, 0xf3, 0x50, 0xad, 0x87, 0xde, 0x95, 0x9e, 0xae, 0x2a, 0xd8, 0xdd, + 0x78, 0x87, 0x96, 0x2b, 0xe0, 0x12, 0x95, 0xd9, 0x3b, 0xb2, 0x2a, 0x06, 0xe2, 0xf0, 0x06, 0xd4 }, + { 0x42, 0x24, 0xdd, 0x0a, 0xd1, 0x11, 0x31, 0x7e, 0x56, 0x45, 0xb0, 0x0e, 0x86, 0xc1, 0x5d, 0x8c, + 0x03, 0x01, 0xb8, 0x33, 0x20, 0xbd, 0x08, 0x10, 0xe5, 0x70, 0x92, 0x2b, 0x5b, 0x86, 0xd3, 0x50, + 0x4c, 0x1e, 0xe3, 0xd1, 0x2a, 0x4e, 0x40, 0x02, 0x19, 0x0b, 0xf6, 0x91, 0xd9, 0x9e, 0xaa, 0x54, + 0x7c, 0x3d, 0xba, 0xc5, 0x5a, 0x9e, 0xb2, 0xbb, 0x4e, 0x0d, 0x5b, 0xdd, 0x90, 0xc9, 0x7b, 0xc2 }, + { 0x54, 0x95, 0xd5, 0xdc, 0x7e, 0x7e, 0xec, 0xd4, 0x67, 0x08, 0xdc, 0x58, 0xa9, 0x80, 0x8a, 0x03, + 0x6a, 0xf8, 0x40, 0xca, 0x0d, 0x5b, 0x6c, 0xe4, 0xc9, 0x71, 0xa5, 0xaf, 0x2a, 0xaa, 0xe8, 0x95, + 0x45, 0xe7, 0xe2, 0xc3, 0x47, 0x84, 0xc6, 0xbe, 0xe5, 0x65, 0xaf, 0xcd, 0x7c, 0x20, 0x5f, 0x8b, + 0x19, 0x61, 0xe4, 0xc9, 0xc1, 0x86, 0xa5, 0x6f, 0x96, 0xf3, 0x9c, 0x13, 0x28, 0x1b, 0xcf, 0x07 }, + { 0xc4, 0x7f, 0xf2, 0x6f, 0xcc, 0x4a, 0xf8, 0xa4, 0x1f, 0x1d, 0x6e, 0x5e, 0x30, 0xb2, 0x99, 0x8f, + 0x5d, 0x7c, 0x26, 0x1c, 0x52, 0x6f, 0xd0, 0x33, 0xa7, 0xf8, 0xca, 0x2a, 0xc3, 0x8c, 0xa8, 0xd1, + 0x50, 0x4f, 0xa7, 0xe8, 0xf2, 0x10, 0x4c, 0xcd, 0x8a, 0x31, 0x03, 0xc8, 0x93, 0x2c, 0xd7, 0xe4, + 0x21, 0xdb, 0xa2, 0x62, 0x7b, 0x1f, 0x28, 0x14, 0x69, 0x7e, 0x87, 0xac, 0xf9, 0xb4, 0x97, 0x00, + 0x62, 0x86, 0x14, 0xd7, 0xe4, 0x65, 0xdd, 0x9e, 0x1c, 0x64, 0x5f, 0x3e, 0xef, 0xfe, 0xa6, 0x60, + 0x68, 0x91, 0x94, 0x8a, 0x1c, 0x89, 0xae, 0xe4, 0xcf, 0x3a, 0xdd, 0xc0, 0xb4, 0x47, 0xe8, 0x8f }, + { 0x12, 0x80, 0x00, 0xda, 0xce, 0xc4, 0x80, 0x8f, 0xa9, 0xa1, 0x5d, 0x98, 0x7d, 0x2c, 0xb2, 0x9c, + 0x71, 0xde, 0x62, 0x89, 0x6a, 0xe1, 0x92, 0xd7, 0x96, 0xdc, 0xcd, 0xc8, 0x08, 0x0e, 0x48, 0xbf, + 0x2a, 0x53, 0x72, 0x90, 0x31, 0x71, 0x49, 0x02, 0xda, 0x4e, 0x19, 0x05, 0x10, 0xcb, 0x41, 0x97, + 0x44, 0xdc, 0x2d, 0x1e, 0x48, 0xe5, 0x0e, 0x41, 0x9d, 0x7d, 0x03, 0xa3, 0xe2, 0x65, 0xd4, 0x01, + 0x62, 0x86, 0x14, 0xd7, 0xe4, 0x65, 0xdd, 0x9e, 0x1c, 0x64, 0x5f, 0x3e, 0xef, 0xfe, 0xa6, 0x60, + 0x68, 0x91, 0x94, 0x8a, 0x1c, 0x89, 0xae, 0xe4, 0xcf, 0x3a, 0xdd, 0xc0, 0xb4, 0x47, 0xe8, 0x8f } }, + { { 0x00, 0x4b, 0x0b, 0xf5, 0x1f, 0x07, 0x1e, 0x23, 0xe3, 0x93, 0x7b, 0x31, 0x41, 0x2a, 0x0a, 0x50, + 0x35, 0xe2, 0xbb, 0xfe, 0x51, 0x77, 0x6c, 0xc9, 0xc5, 0x13, 0xb9, 0x87, 0x79, 0x65, 0x68, 0x20, + 0xcc, 0x09, 0x90, 0xa9, 0xe4, 0xef, 0x9f, 0x1a, 0xe1, 0x69, 0x76, 0x14, 0x82, 0x42, 0x88, 0x4b, + 0xdc, 0xe0, 0x10, 0x22, 0xe2, 0xd6, 0x36, 0x7c, 0x0b, 0xd9, 0x08, 0xea, 0xfa, 0xe4, 0xfd, 0x45 }, + { 0x57, 0x5c, 0x1e, 0x20, 0xb4, 0xae, 0x9e, 0x9d, 0x04, 0xfb, 0x1a, 0xd7, 0x23, 0xd8, 0x8a, 0x6b, + 0x1b, 0xb2, 0xef, 0xa9, 0x06, 0x38, 0xbb, 0x9b, 0x43, 0x2e, 0xf1, 0x81, 0x0b, 0x76, 0xec, 0x20, + 0x46, 0x1b, 0xc4, 0x71, 0x19, 0x3e, 0x79, 0xe8, 0xcf, 0xea, 0xdc, 0x4b, 0x3f, 0x0b, 0xeb, 0x05, + 0x13, 0x1a, 0x2c, 0xfe, 0x16, 0xe9, 0xf0, 0xc4, 0x9c, 0x41, 0xab, 0x45, 0x1b, 0xba, 0x05, 0xec }, + { 0x06, 0x0b, 0x73, 0xec, 0x30, 0x74, 0x0d, 0x8d, 0x13, 0x4b, 0xef, 0xac, 0x3b, 0x05, 0xb6, 0xed, + 0x2b, 0x05, 0xd1, 0xa7, 0x65, 0xb0, 0xcb, 0x69, 0x00, 0xeb, 0x47, 0xe3, 0x1c, 0x07, 0x8b, 0x15, + 0xbf, 0x69, 0xff, 0x27, 0xb4, 0xdb, 0x77, 0xaf, 0xe9, 0x9a, 0xfb, 0xb2, 0x28, 0xa4, 0xf9, 0x05, + 0xe4, 0x3c, 0x66, 0x56, 0x00, 0x1a, 0x2c, 0x41, 0xf2, 0xe1, 0x11, 0x09, 0xfa, 0xe1, 0x50, 0x49 }, + { 0xbc, 0x4d, 0x6f, 0x75, 0x79, 0x77, 0x64, 0x6b, 0xec, 0xac, 0x1a, 0x26, 0x73, 0x9c, 0xf3, 0xf1, + 0x4d, 0x79, 0xbe, 0x6f, 0x0c, 0x07, 0x22, 0xd1, 0xa1, 0x31, 0x75, 0xa8, 0x9c, 0xb6, 0x00, 0x63, + 0x0d, 0x40, 0x17, 0xec, 0x83, 0xda, 0x82, 0x2c, 0x3b, 0xfd, 0x90, 0xe3, 0xbc, 0xc2, 0x2c, 0xf5, + 0x3e, 0x41, 0xe9, 0x98, 0x57, 0xa2, 0xb7, 0xce, 0x5f, 0x31, 0xbb, 0x0b, 0x05, 0x61, 0x0f, 0x55 }, + { 0xb7, 0xab, 0xb2, 0x84, 0xf1, 0x67, 0x24, 0x16, 0x61, 0xe9, 0x20, 0x33, 0x0b, 0xff, 0x22, 0x61, + 0x70, 0xa0, 0x5d, 0xf6, 0xa8, 0x33, 0xc9, 0x30, 0x73, 0xe5, 0x89, 0x36, 0x59, 0xea, 0xa8, 0xe7, + 0x03, 0xf6, 0x14, 0xc1, 0x79, 0xb6, 0x42, 0xa5, 0xc8, 0x6c, 0xb8, 0x94, 0x29, 0x24, 0x00, 0x09, + 0xb5, 0x54, 0x3f, 0xe1, 0x6b, 0xfb, 0x4d, 0x2d, 0xa9, 0x9a, 0x02, 0xa1, 0xa5, 0x09, 0xf4, 0xcb }, + { 0x92, 0xfa, 0x18, 0x84, 0x3e, 0xdb, 0xdf, 0x7d, 0x87, 0xd6, 0x2d, 0x07, 0x05, 0x2c, 0xba, 0xe4, + 0x30, 0x76, 0xa2, 0xe8, 0x71, 0x3b, 0x1b, 0x93, 0x5b, 0xce, 0x2e, 0xec, 0x50, 0x6e, 0x4a, 0x0b, + 0x2d, 0xbe, 0xa3, 0x76, 0x92, 0xf8, 0xc8, 0x4a, 0x71, 0x66, 0xec, 0xfa, 0x36, 0xc5, 0xdb, 0xab, + 0x99, 0x9c, 0xbf, 0x99, 0x07, 0xe8, 0xfe, 0xf4, 0x2f, 0x90, 0x16, 0x5d, 0xdc, 0xbe, 0xfa, 0x08, + 0x93, 0xde, 0x13, 0xf5, 0x32, 0x45, 0x9a, 0xde, 0xa2, 0x5d, 0xb9, 0xe0, 0x38, 0x4c, 0x6a, 0xcc, + 0x13, 0x46, 0x27, 0x28, 0xbf, 0xf8, 0x7a, 0x9c, 0x2e, 0xde, 0x6f, 0xfe, 0xe1, 0x86, 0x41, 0x79 }, + { 0xa7, 0x32, 0x52, 0x76, 0x4f, 0x3e, 0x1b, 0xab, 0x82, 0x18, 0x14, 0xe7, 0x42, 0x32, 0xb8, 0xa4, + 0x98, 0xde, 0xa4, 0xd7, 0xae, 0x42, 0x84, 0xda, 0x71, 0xf7, 0x78, 0x40, 0x56, 0x94, 0x64, 0x49, + 0x34, 0x37, 0xeb, 0xe3, 0x05, 0x4c, 0xb9, 0xbb, 0xce, 0xb2, 0x72, 0xc0, 0x75, 0x1c, 0xc4, 0xd5, + 0x1e, 0x3a, 0xc1, 0x43, 0xda, 0xd1, 0x81, 0x82, 0xa9, 0xd5, 0x0e, 0x0a, 0x5e, 0xc2, 0xd7, 0x04, + 0x93, 0xde, 0x13, 0xf5, 0x32, 0x45, 0x9a, 0xde, 0xa2, 0x5d, 0xb9, 0xe0, 0x38, 0x4c, 0x6a, 0xcc, + 0x13, 0x46, 0x27, 0x28, 0xbf, 0xf8, 0x7a, 0x9c, 0x2e, 0xde, 0x6f, 0xfe, 0xe1, 0x86, 0x41, 0x79 } }, + { { 0xa3, 0xdf, 0x4a, 0xfd, 0xe6, 0x74, 0xb8, 0xeb, 0xed, 0xe7, 0x7e, 0xd2, 0xae, 0xf8, 0x40, 0x80, + 0x3a, 0x55, 0x58, 0x1d, 0x6b, 0xa4, 0x32, 0x6c, 0x15, 0xbb, 0x67, 0xdf, 0x9e, 0xb5, 0x70, 0x4b, + 0x7f, 0x4d, 0xfe, 0x34, 0x42, 0x0c, 0x4d, 0xe3, 0x97, 0x87, 0x6d, 0x08, 0xe8, 0x4d, 0x8a, 0xa9, + 0xbc, 0xbf, 0x1b, 0xb7, 0x66, 0x32, 0xf4, 0x7f, 0x93, 0xca, 0xa4, 0xd2, 0x8f, 0x02, 0x7b, 0xfa }, + { 0xea, 0xac, 0xdf, 0x25, 0x39, 0xf3, 0x28, 0xb6, 0xbe, 0xa8, 0x4a, 0x32, 0x59, 0x4b, 0x4f, 0xb5, + 0xd2, 0xf7, 0xf5, 0x75, 0x43, 0x8b, 0xb3, 0x6a, 0x98, 0x8c, 0x14, 0xc9, 0x3f, 0x7e, 0x5c, 0x05, + 0xf0, 0xeb, 0x1d, 0xc5, 0xe6, 0x1b, 0x5d, 0x7f, 0x38, 0x5d, 0x9a, 0xbe, 0xc8, 0x97, 0x09, 0x65, + 0x62, 0x88, 0x99, 0xda, 0x95, 0x13, 0x93, 0xd9, 0xa3, 0x19, 0x0a, 0xa7, 0x4a, 0xb2, 0x81, 0xa4 }, + { 0x6e, 0x70, 0x65, 0xaa, 0x1b, 0x16, 0xcb, 0xc1, 0x59, 0x6b, 0xc9, 0x4d, 0xd1, 0x0a, 0x9d, 0x8c, + 0x76, 0x70, 0x3c, 0xc1, 0xc1, 0x66, 0xa6, 0x9f, 0xfc, 0xca, 0xb0, 0x3f, 0x0e, 0xe9, 0xa9, 0x36, + 0x09, 0x4f, 0x94, 0xf3, 0x32, 0x25, 0x34, 0xf6, 0xe4, 0xf9, 0x0b, 0x0c, 0xe6, 0xe0, 0x6d, 0x9e, + 0xa5, 0x52, 0x82, 0x9c, 0xd4, 0x43, 0xa4, 0xd1, 0xd1, 0x63, 0x20, 0xce, 0xbc, 0x4f, 0x43, 0xdc }, + { 0x35, 0xd6, 0xc1, 0x68, 0xa6, 0xd7, 0xd3, 0x36, 0x82, 0x2a, 0x0f, 0x29, 0x3e, 0xd6, 0x15, 0x29, + 0x19, 0x73, 0x14, 0x78, 0x87, 0x86, 0xca, 0x9f, 0x6e, 0x17, 0xea, 0xaf, 0x24, 0x37, 0xd6, 0xb4, + 0xb0, 0xee, 0x84, 0x90, 0x2d, 0x18, 0xbd, 0x26, 0xc3, 0xd4, 0x39, 0x4f, 0x45, 0xfa, 0x2f, 0x70, + 0xf2, 0xe2, 0x2a, 0x2a, 0x5c, 0x65, 0x15, 0xcb, 0xaf, 0x92, 0x9a, 0xfc, 0x06, 0xe0, 0x8a, 0x1b }, + { 0x5d, 0xfa, 0xc0, 0x2b, 0xc3, 0x94, 0x19, 0xb4, 0xd6, 0x13, 0xe3, 0xcf, 0x91, 0xad, 0x8c, 0xe1, + 0x97, 0x46, 0xfe, 0xea, 0x74, 0xe0, 0x0c, 0x03, 0xf7, 0x2e, 0x51, 0xa7, 0xf2, 0xbc, 0xce, 0xe8, + 0x6b, 0xfd, 0x2f, 0x54, 0x52, 0x12, 0x00, 0x8d, 0x95, 0x91, 0xc3, 0xf6, 0x25, 0xf8, 0x65, 0x6a, + 0x9c, 0x79, 0x6b, 0x71, 0xc0, 0x0c, 0x29, 0xfb, 0xe7, 0x14, 0x9f, 0x2f, 0x1a, 0x07, 0x53, 0x50 }, + { 0xe9, 0xd4, 0x46, 0x0b, 0x51, 0x3f, 0xf1, 0xbe, 0x0a, 0x23, 0xa5, 0x38, 0xa0, 0xe3, 0x70, 0x14, + 0x63, 0xf0, 0x94, 0xbb, 0x1c, 0x4f, 0x23, 0x05, 0x1b, 0x62, 0x40, 0x9b, 0xf9, 0x52, 0x1b, 0x41, + 0x51, 0x57, 0x2a, 0x99, 0x73, 0xda, 0xe1, 0xcf, 0xc5, 0x4c, 0x65, 0x3a, 0xc2, 0x9d, 0x73, 0xda, + 0xc9, 0x59, 0xf1, 0xdf, 0xab, 0x2b, 0x27, 0xe1, 0x59, 0x8b, 0xa7, 0x48, 0xf9, 0x36, 0xcb, 0x08, + 0xe3, 0x5e, 0x1d, 0xdd, 0xf9, 0x20, 0x4f, 0x64, 0xa9, 0x26, 0x74, 0x97, 0xf2, 0x2d, 0x31, 0xac, + 0x8c, 0x20, 0x77, 0x09, 0xa9, 0x8f, 0xed, 0x23, 0x77, 0x7e, 0xd7, 0x34, 0x93, 0x84, 0xe7, 0xaa }, + { 0xaa, 0xf7, 0x64, 0xdf, 0x34, 0x59, 0x1c, 0x2c, 0xbc, 0x47, 0x08, 0x6a, 0x25, 0xbf, 0x9d, 0x48, + 0x54, 0xcf, 0xa0, 0x6c, 0xfc, 0xd4, 0x10, 0x39, 0x9f, 0x64, 0x46, 0xce, 0xd9, 0x95, 0x28, 0x89, + 0xdf, 0x94, 0x5e, 0x74, 0x0b, 0x55, 0x46, 0x82, 0xd9, 0x3d, 0x82, 0x97, 0x7d, 0xd0, 0x3e, 0xd7, + 0xf6, 0x6f, 0xaa, 0x97, 0x3e, 0xdf, 0xa7, 0xde, 0xe3, 0xc5, 0xaf, 0xd3, 0xa0, 0x5a, 0x30, 0x0d, + 0xe3, 0x5e, 0x1d, 0xdd, 0xf9, 0x20, 0x4f, 0x64, 0xa9, 0x26, 0x74, 0x97, 0xf2, 0x2d, 0x31, 0xac, + 0x8c, 0x20, 0x77, 0x09, 0xa9, 0x8f, 0xed, 0x23, 0x77, 0x7e, 0xd7, 0x34, 0x93, 0x84, 0xe7, 0xaa } }, + { { 0x96, 0x4e, 0xf2, 0x1e, 0x3a, 0xe5, 0x77, 0xbf, 0xa7, 0x1c, 0x3d, 0x66, 0x08, 0x06, 0xca, 0x55, + 0x43, 0x7a, 0x08, 0xf8, 0xff, 0x55, 0xb3, 0xbc, 0x9a, 0x83, 0x9a, 0x2e, 0xe6, 0x97, 0x14, 0x32, + 0x36, 0x57, 0x5c, 0xa4, 0x04, 0x78, 0xb1, 0x92, 0xf4, 0x23, 0x94, 0xe6, 0x2a, 0xef, 0xd4, 0xe7, + 0xc4, 0x02, 0x9f, 0xa9, 0x79, 0x77, 0x61, 0x90, 0xd6, 0xdb, 0x6e, 0x28, 0x7e, 0xc0, 0x1d, 0x70 }, + { 0xc5, 0xd1, 0x5c, 0x34, 0x15, 0xa9, 0x1e, 0x42, 0x2a, 0x1b, 0x0d, 0xf0, 0x56, 0x83, 0x10, 0xc3, + 0xc9, 0x21, 0xfd, 0x05, 0xfa, 0x51, 0x0e, 0x11, 0x28, 0xcc, 0x84, 0xac, 0x35, 0xb5, 0xd8, 0xc8, + 0x5c, 0x80, 0x11, 0x1f, 0x60, 0x1c, 0x72, 0x25, 0x82, 0x45, 0xb5, 0x4f, 0x66, 0x6b, 0x52, 0xb1, + 0xf7, 0x28, 0x0f, 0x80, 0x76, 0x44, 0xdc, 0x15, 0x70, 0x39, 0xe9, 0xaf, 0xc7, 0x0a, 0xa0, 0x43 }, + { 0xff, 0x20, 0x5e, 0x3b, 0x75, 0xe9, 0x38, 0x7c, 0xa3, 0x5c, 0x8b, 0x1a, 0xec, 0x17, 0x8d, 0xf0, + 0xef, 0xb3, 0x53, 0x9b, 0x16, 0xa9, 0x44, 0xf9, 0x34, 0x45, 0x13, 0x66, 0x80, 0x24, 0xdc, 0x22, + 0x0e, 0x51, 0x94, 0xed, 0xe6, 0x83, 0x36, 0x32, 0x63, 0x23, 0x1b, 0xf8, 0x78, 0xb4, 0x04, 0x7f, + 0x5a, 0x50, 0x54, 0x12, 0x19, 0x04, 0x61, 0xdd, 0x25, 0xf0, 0x48, 0x29, 0x04, 0xc1, 0x44, 0xe2 }, + { 0x46, 0x32, 0x2d, 0xc7, 0xbc, 0x05, 0x2a, 0xd3, 0xb5, 0xce, 0x7d, 0x47, 0x5e, 0xfc, 0x90, 0x38, + 0xef, 0xfa, 0x6f, 0x42, 0xf0, 0x66, 0x05, 0x89, 0x7c, 0x9a, 0xc1, 0xfd, 0xa2, 0xe8, 0xa7, 0x38, + 0x18, 0x6d, 0x7f, 0x9e, 0xfb, 0xbd, 0x06, 0x0c, 0x70, 0xd7, 0x29, 0x10, 0x88, 0x04, 0x9f, 0x24, + 0x28, 0x9d, 0xc7, 0x84, 0xdf, 0xb6, 0xec, 0xb2, 0xc7, 0x1b, 0xd1, 0xc1, 0x9d, 0x56, 0xb0, 0x83 }, + { 0xda, 0xd7, 0x34, 0xee, 0x62, 0x13, 0x8f, 0x47, 0xad, 0xb4, 0x9c, 0x98, 0xe4, 0xc5, 0xb3, 0x29, + 0x31, 0x11, 0x64, 0xad, 0xf5, 0x0b, 0x60, 0xe1, 0x0e, 0x18, 0x28, 0x30, 0x3c, 0xa2, 0xe3, 0x29, + 0x89, 0x0a, 0x7e, 0x18, 0xba, 0x30, 0x9e, 0x7d, 0x53, 0xf1, 0x82, 0xd5, 0x27, 0xe5, 0xf3, 0xab, + 0x15, 0xcd, 0x62, 0x7e, 0xdf, 0xf0, 0x0e, 0x42, 0xfa, 0x6b, 0x7b, 0x54, 0xd2, 0x74, 0x19, 0x8f }, + { 0x29, 0x4d, 0x28, 0x80, 0x62, 0xb5, 0x77, 0xbb, 0x69, 0x70, 0xb0, 0xb7, 0x10, 0x2e, 0xed, 0xfc, + 0x13, 0x34, 0x93, 0x7f, 0xd8, 0xfc, 0xb5, 0x7b, 0xfe, 0x34, 0x0a, 0xa3, 0x95, 0x5b, 0xb1, 0xa7, + 0xc6, 0xab, 0x82, 0x79, 0x25, 0x23, 0x94, 0x12, 0xa4, 0x34, 0xec, 0x23, 0xca, 0xcb, 0xd0, 0xa3, + 0xf9, 0x31, 0x32, 0xce, 0x50, 0x31, 0x73, 0x23, 0x98, 0x94, 0xe3, 0x08, 0xd9, 0x1e, 0xc3, 0x0b, + 0x39, 0xe3, 0x3b, 0xf2, 0xe8, 0xb7, 0x26, 0x28, 0x9d, 0xb3, 0x12, 0x8d, 0x16, 0xca, 0x89, 0x26, + 0xa9, 0x1c, 0xa3, 0x1f, 0x36, 0x10, 0x60, 0x6a, 0x29, 0x85, 0xe7, 0x2c, 0xee, 0xc1, 0xb6, 0xae }, + { 0x68, 0xed, 0x3c, 0x64, 0xe6, 0x87, 0xf0, 0x14, 0x64, 0xfc, 0x38, 0x3a, 0x0f, 0xd9, 0x7a, 0x5b, + 0x52, 0x32, 0x10, 0xca, 0xc6, 0x83, 0x0b, 0xae, 0x17, 0x0e, 0xfe, 0x77, 0xe0, 0xe7, 0x83, 0xa1, + 0x2c, 0x78, 0x62, 0x9c, 0x79, 0x08, 0x2b, 0xd4, 0x85, 0x72, 0x27, 0x8d, 0x97, 0x78, 0x62, 0x33, + 0x34, 0xeb, 0x5c, 0xde, 0x5d, 0xaa, 0x4d, 0xfa, 0xd1, 0x67, 0xa4, 0xea, 0x45, 0xad, 0xf9, 0x06, + 0x39, 0xe3, 0x3b, 0xf2, 0xe8, 0xb7, 0x26, 0x28, 0x9d, 0xb3, 0x12, 0x8d, 0x16, 0xca, 0x89, 0x26, + 0xa9, 0x1c, 0xa3, 0x1f, 0x36, 0x10, 0x60, 0x6a, 0x29, 0x85, 0xe7, 0x2c, 0xee, 0xc1, 0xb6, 0xae } }, + { { 0xd9, 0x64, 0xb2, 0xe1, 0x9f, 0x0a, 0x35, 0xfc, 0x9f, 0xc3, 0xa5, 0x2a, 0xa3, 0x84, 0xb4, 0xf3, + 0x23, 0xc4, 0xf3, 0x5a, 0x9d, 0xf8, 0x7f, 0x35, 0xa9, 0xf5, 0x5b, 0x68, 0xfc, 0x19, 0x69, 0x63, + 0x6a, 0x13, 0x19, 0x32, 0xcc, 0x9d, 0x0c, 0x3c, 0x7d, 0xdd, 0x85, 0x16, 0xa8, 0xd9, 0x2b, 0x75, + 0x08, 0x4b, 0x9a, 0xa5, 0x6e, 0xf3, 0xe9, 0xeb, 0xed, 0x5d, 0x2e, 0xfd, 0x2e, 0x0c, 0x60, 0xa2 }, + { 0x0f, 0xf6, 0x8c, 0x3f, 0x6e, 0xee, 0x56, 0x4f, 0x43, 0x6f, 0x54, 0xbd, 0x7a, 0xe4, 0xbe, 0xa8, + 0x77, 0x05, 0x99, 0xe7, 0x9e, 0x59, 0x22, 0x85, 0x9b, 0xc6, 0xe4, 0x2a, 0x61, 0x9c, 0x19, 0xb1, + 0x5a, 0xeb, 0x7a, 0xf8, 0x41, 0x4e, 0xe5, 0x2a, 0xd0, 0xf7, 0x44, 0xf0, 0x16, 0xea, 0x0c, 0x04, + 0x19, 0x6c, 0xb6, 0x30, 0x3c, 0x6e, 0x2d, 0x79, 0x9a, 0x8f, 0x08, 0x90, 0x11, 0xf1, 0xc0, 0x4d }, + { 0x68, 0xe7, 0x1d, 0x40, 0xf1, 0x07, 0xc0, 0xc6, 0xb2, 0x87, 0x9c, 0xa2, 0x19, 0x43, 0x7a, 0xdf, + 0x8a, 0x5a, 0x0f, 0xe2, 0x24, 0x97, 0xa0, 0x38, 0x79, 0x20, 0x38, 0xa9, 0x9c, 0x77, 0xc4, 0x37, + 0xa6, 0x02, 0xe0, 0x93, 0x47, 0xa4, 0x55, 0x21, 0xc2, 0x69, 0xbe, 0x09, 0x05, 0xaa, 0x87, 0x28, + 0xf1, 0x95, 0x2f, 0xdb, 0xf0, 0xbf, 0xd2, 0x9e, 0x5e, 0x3a, 0xfa, 0xc6, 0x2f, 0x13, 0x09, 0xaf }, + { 0xe1, 0x9e, 0xc8, 0x4f, 0xc9, 0xdd, 0x61, 0x60, 0x94, 0xbc, 0xd3, 0xd6, 0xde, 0x11, 0x6e, 0xec, + 0x84, 0xc4, 0xdd, 0xbe, 0x20, 0x46, 0x6c, 0xef, 0xf6, 0x9d, 0x37, 0x07, 0x53, 0x72, 0x57, 0xf9, + 0x02, 0xb5, 0x64, 0x1f, 0xe2, 0x56, 0xa4, 0x38, 0x6d, 0xa4, 0xed, 0x23, 0x9e, 0xa3, 0xf4, 0x4d, + 0x77, 0x52, 0xdc, 0x8c, 0x51, 0xfc, 0x88, 0x18, 0xbc, 0x83, 0x2a, 0xac, 0xc1, 0x1d, 0x3d, 0x59 }, + { 0x08, 0x4f, 0x78, 0x21, 0xfd, 0x4b, 0x85, 0x86, 0x4e, 0x25, 0xdd, 0x47, 0x60, 0x7f, 0x7e, 0xc6, + 0xd3, 0xa1, 0xab, 0x91, 0x3f, 0xeb, 0xf6, 0x40, 0x7e, 0x1b, 0xbd, 0x99, 0x9c, 0x7c, 0x2f, 0x4f, + 0xca, 0x68, 0xa5, 0xf6, 0x8c, 0x1e, 0xcb, 0xb8, 0x76, 0xe2, 0x87, 0x5b, 0x49, 0x68, 0x97, 0x2c, + 0x21, 0x5c, 0x7c, 0x93, 0x79, 0x9a, 0x95, 0xa1, 0x3a, 0x49, 0xc9, 0x6d, 0x34, 0x6b, 0xa1, 0x98 }, + { 0xb9, 0x88, 0x25, 0x9a, 0x3b, 0x53, 0x56, 0xa1, 0x48, 0x0f, 0xf0, 0x92, 0xde, 0x4e, 0x3e, 0x3a, + 0xcf, 0x02, 0xdc, 0x5c, 0xc2, 0xc3, 0x78, 0xad, 0x8a, 0x0c, 0x3c, 0xc7, 0xdd, 0xdd, 0x71, 0x6e, + 0x3f, 0xd9, 0x3a, 0x57, 0x2a, 0x19, 0xa5, 0x3b, 0x5c, 0x46, 0x7b, 0xc9, 0x0f, 0x16, 0xb3, 0x58, + 0xa6, 0x85, 0xfa, 0x91, 0x2c, 0x9a, 0x9c, 0x12, 0xb6, 0xd6, 0x7d, 0x9a, 0xf0, 0x9d, 0xe9, 0x02, + 0xad, 0x12, 0x87, 0xda, 0x85, 0x58, 0x6b, 0xff, 0x68, 0x96, 0x05, 0x33, 0xba, 0x7f, 0x08, 0xf9, + 0xa9, 0xa2, 0xa9, 0x46, 0x43, 0xe5, 0x03, 0x12, 0xe4, 0xbe, 0x74, 0xaa, 0x46, 0x4e, 0x51, 0xb3 }, + { 0x61, 0x70, 0x17, 0x50, 0x26, 0xfa, 0x51, 0x83, 0xe0, 0xca, 0xa9, 0xb1, 0xc3, 0xc4, 0x83, 0xa9, + 0xb6, 0x43, 0x6b, 0x7a, 0x5b, 0xe4, 0x21, 0x5a, 0x6b, 0xd4, 0x34, 0xf8, 0xee, 0x95, 0x86, 0x2d, + 0x03, 0xbf, 0xca, 0xd0, 0xfa, 0x68, 0x53, 0xb2, 0x97, 0x50, 0xad, 0x89, 0x2f, 0x99, 0x63, 0x67, + 0x18, 0x57, 0x1f, 0x57, 0x41, 0xbc, 0xb7, 0xc0, 0x18, 0xe7, 0xb6, 0xf3, 0x0f, 0xc4, 0x49, 0x0d, + 0xad, 0x12, 0x87, 0xda, 0x85, 0x58, 0x6b, 0xff, 0x68, 0x96, 0x05, 0x33, 0xba, 0x7f, 0x08, 0xf9, + 0xa9, 0xa2, 0xa9, 0x46, 0x43, 0xe5, 0x03, 0x12, 0xe4, 0xbe, 0x74, 0xaa, 0x46, 0x4e, 0x51, 0xb3 } }, + { { 0xc5, 0xdf, 0x86, 0x8f, 0xf1, 0xa7, 0xad, 0x57, 0xfd, 0xb4, 0x53, 0xc3, 0x92, 0x1b, 0x9e, 0x2e, + 0xdd, 0xc5, 0xa4, 0x3b, 0x72, 0xa6, 0x9b, 0x4a, 0x15, 0xca, 0x35, 0xed, 0x3c, 0x1a, 0x3b, 0x38, + 0x36, 0xd6, 0xf2, 0x03, 0xb6, 0x97, 0x1f, 0xcb, 0x40, 0x5d, 0x3c, 0x25, 0xfc, 0xe7, 0xff, 0xc6, + 0xbe, 0x61, 0xe1, 0x98, 0x31, 0x13, 0xa9, 0xbe, 0x05, 0x86, 0xfe, 0x5c, 0xf6, 0xcc, 0xaa, 0xf5 }, + { 0xd2, 0x57, 0x19, 0x98, 0xf8, 0x74, 0x90, 0xb7, 0x69, 0x6e, 0xdd, 0x44, 0xf1, 0x8b, 0xb1, 0x9c, + 0xfd, 0x5b, 0x6b, 0xc0, 0x45, 0xf2, 0x49, 0xa5, 0x4b, 0xff, 0x8b, 0x7f, 0x87, 0xe3, 0xf9, 0x71, + 0xab, 0xfa, 0xc8, 0x17, 0xed, 0xeb, 0x19, 0xc6, 0x3c, 0xee, 0x78, 0xba, 0x89, 0x97, 0x49, 0x85, + 0x39, 0x68, 0x29, 0x88, 0x0b, 0x1c, 0xd1, 0x42, 0x8b, 0xe8, 0x1a, 0x3b, 0xeb, 0x4d, 0xef, 0x3b }, + { 0xea, 0xfb, 0xec, 0x27, 0xc3, 0x92, 0xc3, 0x68, 0x0d, 0x3c, 0x5b, 0x20, 0x20, 0x9c, 0x96, 0xa7, + 0x39, 0xfa, 0x80, 0x91, 0xef, 0x86, 0x7d, 0xa8, 0x87, 0xf6, 0xef, 0x14, 0x01, 0x46, 0xf0, 0x68, + 0x0a, 0x8b, 0xae, 0x83, 0x91, 0x7e, 0xa0, 0x14, 0x14, 0xde, 0xf9, 0xa8, 0xfd, 0x67, 0x57, 0x17, + 0x20, 0x46, 0x43, 0x49, 0x07, 0xf0, 0x3e, 0xc8, 0xbe, 0x66, 0xaf, 0x58, 0x3a, 0xbd, 0xd8, 0x00 }, + { 0x35, 0xf5, 0xc8, 0x2c, 0x0e, 0x4b, 0x56, 0xe0, 0xef, 0x08, 0x34, 0x38, 0x57, 0xe9, 0xde, 0xdb, + 0x1d, 0xe1, 0x28, 0x05, 0x01, 0xed, 0x62, 0x3d, 0xa9, 0x6e, 0xea, 0x5b, 0x95, 0x09, 0xe0, 0x04, + 0x46, 0xff, 0xdc, 0x34, 0xf6, 0xf7, 0x63, 0xb1, 0x76, 0xb8, 0x3c, 0x03, 0xef, 0x36, 0x0f, 0x82, + 0x1b, 0x5b, 0x6f, 0xe2, 0x86, 0xd9, 0x10, 0x01, 0xe6, 0x73, 0x75, 0x0d, 0x50, 0x30, 0x11, 0x68 }, + { 0x27, 0xb6, 0x3b, 0x78, 0x79, 0xf3, 0x22, 0x78, 0x8f, 0x0c, 0x14, 0x8b, 0x3f, 0x68, 0xc2, 0xab, + 0x9f, 0x9f, 0x05, 0x70, 0x7e, 0xee, 0x4b, 0x1b, 0x6b, 0xfc, 0x04, 0x72, 0xca, 0xf1, 0x9a, 0xba, + 0xe3, 0x65, 0x9d, 0xdb, 0x01, 0x33, 0xc5, 0xdb, 0xf6, 0x87, 0xe4, 0x73, 0x5a, 0x0f, 0x94, 0xa9, + 0x2e, 0xfe, 0x8f, 0x3e, 0xd1, 0x0a, 0x6d, 0xa1, 0x21, 0x2a, 0x92, 0x8c, 0x4b, 0x43, 0x13, 0x2f }, + { 0xa3, 0xa8, 0x3b, 0xb4, 0x4f, 0x8a, 0xac, 0xab, 0x8a, 0x4c, 0x39, 0x7e, 0xb8, 0x2f, 0xb1, 0x01, + 0x2e, 0xbe, 0x0e, 0x7d, 0x28, 0x8a, 0x18, 0x4a, 0xda, 0x58, 0x1a, 0xfb, 0x95, 0x97, 0xf3, 0x63, + 0x58, 0xbe, 0x8c, 0x30, 0x13, 0x9b, 0xba, 0x9f, 0x4e, 0xac, 0x8d, 0x95, 0xf2, 0x07, 0xbb, 0x85, + 0xa1, 0x41, 0x4c, 0x33, 0xe3, 0x58, 0x8e, 0x5c, 0xa1, 0x05, 0x45, 0xab, 0x5c, 0x0c, 0xe4, 0x02, + 0xc3, 0xa0, 0xa0, 0x72, 0xdb, 0x9a, 0x9d, 0xbf, 0x13, 0x29, 0x94, 0x70, 0x8b, 0xe4, 0xe8, 0xdb, + 0x0e, 0x0b, 0xd0, 0xa0, 0x25, 0xad, 0x71, 0xa0, 0x27, 0x9c, 0x1d, 0x77, 0xb0, 0x98, 0xa8, 0x03 }, + { 0xe1, 0x84, 0xa5, 0xea, 0xa5, 0xd8, 0x1b, 0x29, 0xce, 0xd7, 0xa3, 0x72, 0xa7, 0xc9, 0xa5, 0xea, + 0xf1, 0x02, 0xf3, 0x0c, 0xb0, 0x65, 0x12, 0xbc, 0xa4, 0xf2, 0x5d, 0x69, 0x00, 0xa4, 0x7f, 0x5a, + 0x52, 0x09, 0xb6, 0x7b, 0x30, 0xf2, 0x99, 0x03, 0x39, 0x9d, 0xee, 0x6f, 0xb5, 0xf7, 0x9e, 0x7a, + 0x97, 0x8b, 0x81, 0x03, 0x8c, 0xdd, 0x35, 0xfc, 0x1f, 0x0a, 0xc6, 0xa4, 0x60, 0x7b, 0xc8, 0x0a, + 0xc3, 0xa0, 0xa0, 0x72, 0xdb, 0x9a, 0x9d, 0xbf, 0x13, 0x29, 0x94, 0x70, 0x8b, 0xe4, 0xe8, 0xdb, + 0x0e, 0x0b, 0xd0, 0xa0, 0x25, 0xad, 0x71, 0xa0, 0x27, 0x9c, 0x1d, 0x77, 0xb0, 0x98, 0xa8, 0x03 } }, + { { 0x67, 0xe9, 0x62, 0x76, 0x3a, 0x90, 0x9b, 0x6b, 0x19, 0x1d, 0x65, 0xb2, 0x2a, 0x2f, 0xf7, 0x50, + 0xaa, 0x54, 0xa5, 0xbb, 0x53, 0xb5, 0xf9, 0xee, 0x0c, 0x04, 0x3a, 0x3c, 0x29, 0x4b, 0x66, 0x3e, + 0x7b, 0xb6, 0xaa, 0xd2, 0x10, 0x89, 0xcc, 0x89, 0x2c, 0x47, 0xbe, 0x23, 0xd6, 0x52, 0x81, 0x5d, + 0xc8, 0xbc, 0x49, 0xd6, 0x6a, 0xcd, 0x62, 0x99, 0x30, 0xff, 0x16, 0xa5, 0x50, 0x44, 0xd8, 0x7a }, + { 0xd6, 0xcd, 0xfe, 0xd4, 0x44, 0x4a, 0x9e, 0x90, 0x44, 0x73, 0x8a, 0xff, 0xbb, 0x82, 0x08, 0xb6, + 0x7f, 0xf2, 0x87, 0xcb, 0xa5, 0x0b, 0x56, 0xd3, 0x9e, 0x91, 0xb8, 0x52, 0x6b, 0x25, 0xa6, 0x5d, + 0x50, 0xaf, 0x9b, 0xd5, 0xfb, 0x9f, 0x7e, 0x2d, 0x57, 0xdf, 0x30, 0x78, 0x8d, 0x1a, 0xc3, 0xac, + 0x9c, 0x5a, 0xbf, 0xab, 0x5a, 0x0d, 0xc9, 0xb6, 0x4b, 0x18, 0xd4, 0xe7, 0x55, 0x40, 0xde, 0x7e }, + { 0xc2, 0xa9, 0x7e, 0x5c, 0x26, 0xf4, 0x7d, 0xce, 0x9e, 0x73, 0xae, 0x50, 0xde, 0xe7, 0xa6, 0xf9, + 0x8b, 0x57, 0xf9, 0x7a, 0x4c, 0x38, 0x82, 0xf6, 0x30, 0x80, 0x12, 0xf7, 0xf6, 0x66, 0x80, 0x46, + 0x4d, 0x41, 0x53, 0x63, 0xd9, 0x65, 0x90, 0xe7, 0xee, 0x24, 0x07, 0xb0, 0x4f, 0xeb, 0x3e, 0x8e, + 0x83, 0x21, 0xa3, 0x40, 0x03, 0xc0, 0x64, 0x52, 0xc6, 0xb2, 0x12, 0x9d, 0x8d, 0x86, 0xdd, 0x19 }, + { 0xe2, 0xd5, 0x49, 0x5e, 0x2a, 0x6e, 0x4e, 0xd9, 0x31, 0x26, 0x53, 0x13, 0x98, 0x5e, 0x2f, 0x23, + 0xea, 0xa0, 0x30, 0xee, 0xef, 0x62, 0x2b, 0xdc, 0x93, 0x65, 0x90, 0xad, 0x9a, 0xf1, 0x74, 0x12, + 0xf5, 0x24, 0x33, 0xcc, 0xc3, 0xda, 0x42, 0x54, 0xa6, 0x6c, 0x86, 0x99, 0xb9, 0xb5, 0xf7, 0x07, + 0x90, 0xd8, 0x85, 0x7f, 0x69, 0xfb, 0x19, 0x2a, 0x2c, 0xc0, 0x11, 0x81, 0x64, 0x37, 0x38, 0x07 }, + { 0xc7, 0xb3, 0xf5, 0xe4, 0x4b, 0x55, 0xcf, 0xd8, 0x2b, 0x72, 0xde, 0x62, 0xfc, 0x66, 0xea, 0x82, + 0xee, 0x2e, 0xe5, 0x4f, 0x66, 0xba, 0x19, 0x63, 0x01, 0x0b, 0x2d, 0x89, 0xb4, 0xaa, 0x76, 0xb3, + 0x7e, 0xc5, 0xbe, 0xdd, 0x57, 0x90, 0x5e, 0xff, 0x5b, 0x9a, 0x71, 0xe1, 0x47, 0xf9, 0xec, 0xe5, + 0xf0, 0x19, 0x89, 0x17, 0x65, 0x3e, 0x56, 0x4a, 0x98, 0xb2, 0x3c, 0x3b, 0xf0, 0x14, 0x13, 0x1b }, + { 0xc0, 0x72, 0x26, 0x96, 0x6b, 0xf5, 0x50, 0xa1, 0x65, 0xcd, 0xfe, 0x92, 0xa5, 0x5a, 0xb3, 0x56, + 0x27, 0x5b, 0x2f, 0x4a, 0x8f, 0x67, 0xaa, 0xf4, 0xa1, 0x6e, 0x3c, 0x66, 0xcc, 0xb7, 0x71, 0x70, + 0xff, 0x70, 0x1f, 0x9e, 0x09, 0xae, 0x31, 0xcb, 0x2a, 0xd5, 0x8a, 0x38, 0xa9, 0xaf, 0xbc, 0x94, + 0xa2, 0xa8, 0xe9, 0x77, 0x1c, 0xc3, 0xfa, 0xd1, 0x45, 0xd2, 0xe2, 0xff, 0x7d, 0xf2, 0x44, 0x00, + 0xa0, 0xc3, 0xc1, 0xdd, 0xa0, 0x4c, 0xfb, 0xed, 0x1a, 0xbd, 0x0c, 0x05, 0x3b, 0xa9, 0xc8, 0x98, + 0xb0, 0x7d, 0x6a, 0x77, 0xcb, 0x08, 0x70, 0x64, 0x31, 0x9d, 0x9c, 0x7b, 0x40, 0x9e, 0xbb, 0xf4 }, + { 0xbc, 0x88, 0x9d, 0x36, 0xae, 0xbc, 0x92, 0x47, 0x63, 0x85, 0x41, 0xe3, 0x1e, 0x1c, 0x39, 0xf5, + 0xd3, 0xc2, 0x0a, 0x7d, 0x18, 0x7a, 0x8f, 0xd3, 0x0c, 0x37, 0x50, 0x28, 0x35, 0x93, 0x77, 0x4b, + 0xcb, 0xba, 0x35, 0x4e, 0x94, 0x48, 0xe4, 0x0c, 0xa7, 0x36, 0x4f, 0x74, 0x2b, 0xf9, 0xb5, 0xb5, + 0xeb, 0x91, 0x50, 0x3c, 0x67, 0x9b, 0x4d, 0x25, 0xd4, 0x0e, 0x0d, 0xb9, 0x5b, 0x77, 0xf3, 0x0e, + 0xa0, 0xc3, 0xc1, 0xdd, 0xa0, 0x4c, 0xfb, 0xed, 0x1a, 0xbd, 0x0c, 0x05, 0x3b, 0xa9, 0xc8, 0x98, + 0xb0, 0x7d, 0x6a, 0x77, 0xcb, 0x08, 0x70, 0x64, 0x31, 0x9d, 0x9c, 0x7b, 0x40, 0x9e, 0xbb, 0xf4 } }, + { { 0x44, 0xdd, 0x62, 0x9e, 0x0f, 0xee, 0x20, 0x11, 0x37, 0xfc, 0xd0, 0x5c, 0xe4, 0xe1, 0x0a, 0xb8, + 0xc2, 0xe0, 0x9c, 0x2c, 0x3e, 0x1b, 0x31, 0x1c, 0xdb, 0xa3, 0x84, 0x9a, 0xb7, 0x4e, 0x40, 0x74, + 0x21, 0xfd, 0xfc, 0x65, 0xbd, 0x38, 0x8a, 0x55, 0x6f, 0x1e, 0xc3, 0x14, 0xfc, 0x66, 0x04, 0x7b, + 0xc4, 0x61, 0xb0, 0xcb, 0xfa, 0xdd, 0x50, 0x45, 0x4b, 0x2e, 0xf0, 0x6d, 0x0f, 0x26, 0x6d, 0xbf }, + { 0xe6, 0xbc, 0x35, 0x73, 0xb3, 0x11, 0x38, 0xc6, 0x31, 0x82, 0x96, 0x80, 0x1d, 0xa9, 0xd9, 0x17, + 0x85, 0x4e, 0xad, 0x0f, 0x5c, 0xb7, 0xe8, 0x78, 0x62, 0x2f, 0x3c, 0x10, 0x0e, 0xdc, 0xf2, 0x7e, + 0xf5, 0x02, 0x6d, 0x1a, 0x50, 0xc2, 0x50, 0x7d, 0x0d, 0x14, 0x77, 0x77, 0xfc, 0xbe, 0x23, 0x02, + 0x81, 0x0a, 0xdc, 0xa3, 0x16, 0xfd, 0xab, 0xb9, 0x7c, 0xb6, 0x7e, 0x8a, 0xde, 0x1f, 0x22, 0xeb }, + { 0xab, 0xf3, 0xea, 0x63, 0xc0, 0x25, 0xa2, 0xc7, 0x6a, 0xfe, 0x91, 0x4a, 0x0a, 0x91, 0xdd, 0x6d, + 0x6f, 0x8c, 0xf9, 0xa8, 0x1c, 0x9f, 0xb5, 0xe5, 0xd2, 0xac, 0xe6, 0x51, 0x9a, 0xd3, 0x87, 0x17, + 0x82, 0x12, 0x0a, 0x58, 0x99, 0x7f, 0x81, 0x2d, 0x8d, 0x27, 0x2d, 0x1b, 0xb0, 0x02, 0x7e, 0x0d, + 0xd6, 0x18, 0x89, 0x5e, 0x0c, 0x2b, 0x57, 0xa6, 0x56, 0x35, 0xff, 0x71, 0x4e, 0xb0, 0x49, 0x38 }, + { 0x36, 0xdf, 0x1d, 0x1c, 0xf6, 0xa7, 0x4d, 0x87, 0x7e, 0x2c, 0x3f, 0xb4, 0xda, 0xd7, 0x80, 0x71, + 0x0b, 0xf3, 0x2a, 0x47, 0x20, 0xe6, 0x9a, 0x3d, 0x17, 0x9a, 0x97, 0xc9, 0x4e, 0x53, 0xa6, 0xe2, + 0x23, 0xea, 0x94, 0x4d, 0xf9, 0xeb, 0x2c, 0x03, 0x2c, 0x88, 0xa2, 0xe6, 0xc5, 0x94, 0xa5, 0x6f, + 0xc3, 0x98, 0xa9, 0x8b, 0xa7, 0x41, 0x7d, 0xd3, 0x82, 0x01, 0x13, 0xb6, 0x0f, 0x39, 0x1e, 0xd2 }, + { 0x08, 0x28, 0xc3, 0x1c, 0xec, 0x21, 0x3a, 0xb4, 0x4c, 0xb1, 0xfa, 0xb9, 0x0c, 0xfe, 0xc2, 0x50, + 0xc5, 0x99, 0x62, 0xa0, 0x11, 0x74, 0xcf, 0x05, 0x1e, 0x2b, 0xdf, 0x6d, 0x22, 0x8e, 0x6e, 0x55, + 0x19, 0x21, 0x9c, 0xa1, 0x98, 0x56, 0x45, 0x90, 0x40, 0x3a, 0x8e, 0xad, 0x76, 0x4d, 0xd3, 0x95, + 0x27, 0x67, 0x4e, 0x02, 0x16, 0xc3, 0xfe, 0x5a, 0x79, 0x4e, 0x2d, 0x6f, 0xd0, 0xe4, 0x4f, 0x62 }, + { 0x40, 0x14, 0xe1, 0x88, 0x3d, 0xcc, 0x51, 0xcb, 0x98, 0x86, 0x06, 0x4d, 0xe4, 0x52, 0x71, 0xe2, + 0x2e, 0x2b, 0x80, 0xfd, 0x81, 0x65, 0xaf, 0x93, 0x31, 0x87, 0xe0, 0xff, 0x31, 0xab, 0xff, 0x53, + 0x0e, 0x2d, 0xb1, 0x47, 0xe6, 0x44, 0xb7, 0x29, 0xab, 0x0f, 0x51, 0x3a, 0x53, 0x84, 0x36, 0x58, + 0x8c, 0x5f, 0x7b, 0x65, 0x6a, 0xb7, 0x6f, 0xdc, 0xad, 0xc1, 0xa3, 0xe4, 0x21, 0xfc, 0x22, 0x0e, + 0xc1, 0x10, 0xd1, 0x7d, 0x9f, 0xd3, 0x1e, 0x33, 0xb4, 0xca, 0xb9, 0xff, 0xd8, 0x27, 0xb8, 0xca, + 0xde, 0x49, 0x6f, 0xdc, 0xf0, 0xe8, 0x70, 0x36, 0xdb, 0x90, 0x00, 0x07, 0x9e, 0x77, 0x39, 0xfe }, + { 0xc9, 0x93, 0x4b, 0xe6, 0x47, 0x7e, 0x1d, 0x86, 0x15, 0x46, 0xe8, 0x27, 0xf5, 0x84, 0x67, 0x4e, + 0x42, 0xe3, 0x2b, 0x8a, 0x4e, 0x90, 0x7b, 0x87, 0xcc, 0xdf, 0xaa, 0x04, 0x06, 0x05, 0xe6, 0x72, + 0xff, 0x6f, 0x44, 0x1b, 0x08, 0xad, 0x79, 0x3e, 0xb7, 0xdd, 0xd7, 0x2c, 0x73, 0xf0, 0xf0, 0xc4, + 0x6e, 0xb7, 0x37, 0xe1, 0x02, 0xf5, 0x42, 0xe7, 0xef, 0xa1, 0xdd, 0x50, 0x9a, 0xc5, 0x8d, 0x00, + 0xc1, 0x10, 0xd1, 0x7d, 0x9f, 0xd3, 0x1e, 0x33, 0xb4, 0xca, 0xb9, 0xff, 0xd8, 0x27, 0xb8, 0xca, + 0xde, 0x49, 0x6f, 0xdc, 0xf0, 0xe8, 0x70, 0x36, 0xdb, 0x90, 0x00, 0x07, 0x9e, 0x77, 0x39, 0xfe } }, + { { 0x3e, 0x0c, 0x21, 0xc4, 0x3d, 0x64, 0x61, 0xc1, 0x9d, 0xa1, 0x83, 0x10, 0x74, 0x1d, 0x56, 0x12, + 0xaf, 0x29, 0x5c, 0x6c, 0x12, 0x48, 0x0a, 0xc7, 0xe5, 0x12, 0xb6, 0x42, 0x6b, 0x54, 0xf4, 0x42, + 0x0c, 0x43, 0x42, 0x2e, 0x78, 0xc2, 0xe7, 0x26, 0x09, 0x41, 0x4a, 0x2f, 0xa1, 0xb0, 0x1f, 0xcd, + 0x63, 0x76, 0x1e, 0xa1, 0x6f, 0xf6, 0xe2, 0xc2, 0x08, 0x89, 0x0d, 0x28, 0xbf, 0x1b, 0x56, 0x5b }, + { 0x3e, 0x2e, 0xf2, 0xcc, 0x81, 0xca, 0xa7, 0x5d, 0x01, 0xd2, 0x82, 0xfd, 0x45, 0xee, 0xc0, 0xf5, + 0x49, 0x3b, 0xe2, 0xa4, 0x2a, 0x4d, 0x5f, 0x40, 0x0d, 0xbc, 0xb9, 0x3d, 0x6e, 0xda, 0xe2, 0x86, + 0xe1, 0x23, 0x8b, 0x5f, 0x0d, 0xa2, 0x35, 0x15, 0x1d, 0x22, 0x23, 0xa5, 0x69, 0x56, 0x34, 0x78, + 0xb3, 0xb3, 0x55, 0xef, 0x63, 0x8a, 0x17, 0x63, 0xda, 0xf0, 0x64, 0x99, 0x8a, 0x8a, 0xba, 0xd6 }, + { 0x68, 0x79, 0x36, 0xa7, 0x6b, 0xe3, 0x76, 0x1c, 0xe3, 0x38, 0x0b, 0xa3, 0x91, 0xb6, 0xb0, 0x82, + 0x37, 0xfa, 0x52, 0x74, 0xf1, 0xb5, 0xd5, 0xd9, 0x07, 0x06, 0x9e, 0xda, 0x87, 0x6b, 0x0f, 0x24, + 0x4f, 0xbe, 0xc9, 0xff, 0x03, 0x41, 0xaf, 0x77, 0x68, 0xed, 0xe7, 0x71, 0xba, 0x2d, 0xde, 0x27, + 0xa1, 0xbf, 0xa8, 0xa7, 0x30, 0x7c, 0xcb, 0x79, 0x72, 0x89, 0x1a, 0xdc, 0xc1, 0xe4, 0xb2, 0x9d }, + { 0x94, 0xa3, 0x11, 0xf4, 0x44, 0x80, 0xd0, 0xa3, 0x47, 0x93, 0x36, 0xe2, 0xbd, 0x04, 0xe4, 0x74, + 0x3d, 0x00, 0x60, 0xad, 0xd0, 0x2d, 0x86, 0x66, 0xa1, 0x72, 0x1a, 0xb9, 0x1c, 0x14, 0xa2, 0x9b, + 0x4b, 0x04, 0x7d, 0x5b, 0xcd, 0xf8, 0x01, 0x33, 0xde, 0x34, 0x10, 0x29, 0xc4, 0x72, 0x56, 0xff, + 0x11, 0xcd, 0xd8, 0x61, 0x2c, 0xb6, 0xb7, 0xf4, 0x24, 0x8b, 0x44, 0xb4, 0xe7, 0x34, 0x50, 0xb8 }, + { 0x72, 0xf6, 0xd4, 0xa3, 0x24, 0xf9, 0xef, 0xf4, 0x55, 0x8d, 0x3c, 0x07, 0xca, 0x10, 0xdd, 0x54, + 0x87, 0x13, 0x32, 0x78, 0x5c, 0x64, 0x10, 0x08, 0x62, 0x7e, 0xf4, 0x34, 0x0f, 0x1c, 0xcd, 0xcc, + 0x3b, 0x42, 0xfe, 0x60, 0x41, 0x70, 0x2c, 0x6b, 0xd4, 0x6c, 0xf7, 0xb8, 0x24, 0xf6, 0xd7, 0x07, + 0xb3, 0x46, 0xb0, 0x7d, 0x14, 0x24, 0x9b, 0x72, 0x79, 0xf4, 0x23, 0x2a, 0xec, 0x02, 0xe7, 0x69 }, + { 0xe5, 0xbe, 0x84, 0xc3, 0x92, 0x47, 0x15, 0xd3, 0xac, 0x06, 0x44, 0x72, 0x41, 0xeb, 0xb6, 0x5a, + 0x17, 0x06, 0x90, 0xd9, 0x55, 0x3d, 0xe4, 0x87, 0x7d, 0x5a, 0x11, 0x9f, 0x02, 0x6d, 0xd3, 0x4e, + 0x71, 0xd1, 0x5e, 0x16, 0x9f, 0xb2, 0xc0, 0x7f, 0xcb, 0x78, 0x8b, 0x89, 0x11, 0xae, 0x43, 0xe8, + 0x85, 0xb7, 0xf9, 0xc8, 0x48, 0x5a, 0xb2, 0x96, 0xaf, 0x8f, 0xab, 0x71, 0x84, 0x9d, 0x40, 0x09, + 0x30, 0xd4, 0x32, 0x6e, 0xa2, 0x77, 0x97, 0x71, 0x37, 0xce, 0x22, 0x6b, 0xca, 0xc9, 0x79, 0xef, + 0xc0, 0xb2, 0xb4, 0x3d, 0x30, 0xbf, 0x77, 0xe9, 0xc3, 0x8d, 0xec, 0x15, 0x04, 0x08, 0xfa, 0x15 }, + { 0x4b, 0xf3, 0x7f, 0xb2, 0x78, 0x75, 0x45, 0xd4, 0xce, 0x5e, 0x3d, 0xaf, 0x92, 0x63, 0x3d, 0x90, + 0xc0, 0xa7, 0x23, 0x62, 0x7f, 0x37, 0x58, 0x8d, 0x12, 0xe0, 0xb8, 0x6c, 0x46, 0x38, 0xaa, 0xf7, + 0xe1, 0x03, 0x9e, 0x1f, 0x31, 0xf9, 0x5a, 0xa4, 0x59, 0x0d, 0xec, 0xc5, 0x1f, 0x17, 0x88, 0x25, + 0xcc, 0xed, 0x69, 0x2b, 0x91, 0x73, 0x6a, 0x3f, 0xcb, 0xe5, 0x9c, 0x1e, 0x26, 0x3e, 0xec, 0x0b, + 0x30, 0xd4, 0x32, 0x6e, 0xa2, 0x77, 0x97, 0x71, 0x37, 0xce, 0x22, 0x6b, 0xca, 0xc9, 0x79, 0xef, + 0xc0, 0xb2, 0xb4, 0x3d, 0x30, 0xbf, 0x77, 0xe9, 0xc3, 0x8d, 0xec, 0x15, 0x04, 0x08, 0xfa, 0x15 } }, + { { 0xc5, 0x1d, 0xcd, 0x70, 0xb2, 0x9e, 0x53, 0x29, 0x05, 0x78, 0x83, 0x5d, 0x56, 0x30, 0x89, 0xee, + 0x02, 0xd7, 0xac, 0x57, 0x0a, 0xd2, 0xa0, 0x9c, 0x96, 0x0c, 0xbf, 0xf2, 0x30, 0xbf, 0x1a, 0x2b, + 0xee, 0x0e, 0x9f, 0x1e, 0x1c, 0x65, 0x7d, 0xb5, 0x48, 0xad, 0x6f, 0x51, 0xa0, 0x91, 0x61, 0xe4, + 0xe6, 0x83, 0x9f, 0x58, 0x7c, 0x76, 0x2b, 0x52, 0x94, 0x87, 0x3c, 0x8d, 0x36, 0x4c, 0x37, 0x3c }, + { 0x59, 0x3b, 0x0d, 0x38, 0xab, 0x93, 0xca, 0xfb, 0x67, 0x44, 0x30, 0x96, 0xec, 0xbd, 0x00, 0x1d, + 0x93, 0xd0, 0xb3, 0x3d, 0x3c, 0xd4, 0x4e, 0x3d, 0xd8, 0x29, 0x93, 0xb2, 0xb3, 0x77, 0xfc, 0x57, + 0x31, 0x20, 0xe3, 0x90, 0x0d, 0xf4, 0x91, 0x2f, 0x8b, 0x43, 0xce, 0xfe, 0x99, 0x03, 0x03, 0xa2, + 0x90, 0x8d, 0xcf, 0xa8, 0xc0, 0x21, 0x00, 0xca, 0xcc, 0xcb, 0x4b, 0x2f, 0xa5, 0x39, 0xa8, 0x0b }, + { 0xca, 0xf6, 0xf9, 0xbb, 0x53, 0xcb, 0x97, 0x76, 0xb6, 0x9c, 0x2c, 0x18, 0x21, 0x43, 0x13, 0x48, + 0x13, 0xc9, 0x0e, 0xeb, 0x40, 0xea, 0xce, 0x1f, 0x3a, 0xe9, 0xd2, 0x9e, 0x29, 0xdb, 0xe2, 0x79, + 0xe2, 0x1a, 0x9f, 0x84, 0x9d, 0xe4, 0x55, 0x82, 0x17, 0xeb, 0x87, 0xf6, 0xc3, 0xef, 0xcd, 0x54, + 0x14, 0xee, 0xc8, 0x5b, 0xd7, 0x67, 0x05, 0xe2, 0x34, 0xa2, 0x7e, 0x81, 0x83, 0x21, 0x7a, 0x02 }, + { 0xc5, 0x03, 0xd9, 0x75, 0xdf, 0x17, 0x15, 0xe3, 0x5b, 0x7b, 0x4f, 0x66, 0x9c, 0x15, 0x4e, 0x01, + 0xdf, 0x3d, 0x16, 0xb6, 0x52, 0xcc, 0xcf, 0x28, 0x40, 0xdb, 0x20, 0xee, 0x8b, 0x69, 0xb1, 0x2b, + 0xc0, 0x6e, 0xe4, 0xd2, 0xf5, 0xd1, 0x49, 0x3f, 0xf3, 0x0a, 0x12, 0xcd, 0x13, 0xbd, 0x9d, 0x3d, + 0x5b, 0x28, 0x5c, 0xb0, 0x0d, 0x0e, 0xb6, 0xed, 0xec, 0x65, 0xeb, 0x25, 0x28, 0x2e, 0x65, 0x2f }, + { 0xed, 0xa7, 0x05, 0xc1, 0xa6, 0x81, 0xf2, 0x7a, 0x69, 0x68, 0x17, 0x8e, 0xf7, 0xc9, 0x14, 0x80, + 0x9f, 0x81, 0xfe, 0x16, 0xfd, 0x81, 0x93, 0xb4, 0x0b, 0x05, 0x5b, 0x4e, 0xef, 0x6e, 0x7a, 0x67, + 0x9d, 0x99, 0x4c, 0x17, 0xcd, 0x1c, 0x16, 0xfd, 0x31, 0x35, 0xd5, 0x3e, 0xa3, 0x00, 0xbf, 0xbe, + 0xda, 0xd6, 0xe2, 0x37, 0x9b, 0x13, 0x1b, 0xca, 0x29, 0x90, 0x4b, 0xf2, 0x09, 0x57, 0x2f, 0xe9 }, + { 0xd7, 0xba, 0x23, 0xd3, 0xa0, 0x6e, 0x14, 0x6a, 0xf0, 0x77, 0xb7, 0xe6, 0xe3, 0xc9, 0x3b, 0x38, + 0xbb, 0xe7, 0xbe, 0x54, 0x75, 0xf8, 0xb7, 0x42, 0x29, 0xe2, 0x83, 0xde, 0x20, 0x22, 0x41, 0xcf, + 0x5f, 0x6f, 0x80, 0x60, 0xf3, 0x44, 0x04, 0x21, 0xd5, 0x03, 0x68, 0x42, 0xde, 0x81, 0xea, 0xe8, + 0x7e, 0x5b, 0x80, 0x0f, 0x1b, 0x2d, 0x06, 0xc7, 0xce, 0xe9, 0x46, 0xc7, 0xf7, 0xb3, 0xa2, 0x02, + 0x21, 0xb5, 0x4d, 0xc2, 0x36, 0xea, 0xe6, 0x7b, 0xb3, 0x61, 0xe6, 0x18, 0x40, 0x5b, 0xce, 0x5b, + 0xc2, 0xee, 0xa5, 0xde, 0xe9, 0xe6, 0xe0, 0xa8, 0x58, 0x58, 0x03, 0x34, 0x26, 0x27, 0x65, 0x2a }, + { 0xfa, 0x43, 0xa6, 0xc4, 0x32, 0xa1, 0x2f, 0xb6, 0x37, 0x05, 0xf4, 0xa4, 0xa7, 0x36, 0xdd, 0x1c, + 0x45, 0x10, 0x95, 0x83, 0x67, 0x89, 0x79, 0x18, 0x34, 0xad, 0xe7, 0x57, 0x7f, 0x0d, 0x48, 0x9b, + 0x14, 0xdf, 0x5f, 0xc8, 0xd7, 0x0f, 0x78, 0x47, 0x88, 0x20, 0xff, 0x7f, 0xb1, 0x21, 0x27, 0x14, + 0x58, 0x32, 0x12, 0xfb, 0x97, 0xe0, 0x81, 0x0e, 0x92, 0xf4, 0x5c, 0x0e, 0x44, 0x48, 0x4e, 0x01, + 0x21, 0xb5, 0x4d, 0xc2, 0x36, 0xea, 0xe6, 0x7b, 0xb3, 0x61, 0xe6, 0x18, 0x40, 0x5b, 0xce, 0x5b, + 0xc2, 0xee, 0xa5, 0xde, 0xe9, 0xe6, 0xe0, 0xa8, 0x58, 0x58, 0x03, 0x34, 0x26, 0x27, 0x65, 0x2a } }, + { { 0x1e, 0x89, 0x12, 0xe8, 0xab, 0xca, 0xeb, 0x96, 0x78, 0x43, 0x89, 0x79, 0x26, 0x61, 0x86, 0x2e, + 0x37, 0xd7, 0x94, 0xb5, 0xb9, 0xf7, 0xc9, 0xe7, 0x04, 0x6c, 0x96, 0x1c, 0x54, 0x0d, 0xb0, 0x6c, + 0xd3, 0x68, 0x9b, 0x53, 0xa7, 0x56, 0x34, 0x1b, 0x65, 0xff, 0xf9, 0xee, 0xf1, 0xc6, 0xfd, 0x7e, + 0xa8, 0x42, 0x59, 0x60, 0x06, 0x5f, 0xc2, 0x89, 0x8b, 0xfc, 0xf8, 0x6c, 0x9a, 0x0d, 0xb1, 0x36 }, + { 0x52, 0x3d, 0x83, 0x25, 0x0f, 0x57, 0x81, 0x76, 0x7b, 0x21, 0xf7, 0x96, 0xd6, 0x1f, 0xfe, 0xd7, + 0x7c, 0xc1, 0x32, 0xb5, 0xbc, 0x05, 0x46, 0xdb, 0x6f, 0x25, 0xd8, 0x7a, 0x68, 0xe2, 0x01, 0x81, + 0xf8, 0x9a, 0xc5, 0x29, 0x78, 0x1c, 0x01, 0xc5, 0x4d, 0x61, 0x4e, 0x75, 0xdf, 0x9f, 0xc3, 0x22, + 0x96, 0x7c, 0xf9, 0xa7, 0xed, 0x41, 0x6f, 0x64, 0xfd, 0xd4, 0x61, 0x58, 0x0d, 0x49, 0xc9, 0xa4 }, + { 0x4a, 0xf7, 0xda, 0xef, 0xe0, 0x3b, 0x33, 0x19, 0x79, 0x02, 0x7a, 0xbb, 0xd3, 0x53, 0xf4, 0x8c, + 0x8a, 0x16, 0xfb, 0xbd, 0x35, 0xd9, 0x70, 0xb2, 0x0a, 0x06, 0x05, 0x14, 0xd0, 0x9e, 0xf6, 0x13, + 0x44, 0xbb, 0xb7, 0x93, 0x86, 0x1b, 0x3c, 0xb0, 0x54, 0xa7, 0x48, 0xc2, 0xa7, 0x10, 0xda, 0x65, + 0xb2, 0xdb, 0x0f, 0x85, 0x23, 0x57, 0x77, 0x44, 0x23, 0x20, 0x6d, 0x2e, 0xde, 0x20, 0x01, 0xed }, + { 0x9c, 0xb8, 0x68, 0xeb, 0xbb, 0x8b, 0xaf, 0x81, 0x9c, 0x2f, 0x90, 0x4c, 0xc2, 0x62, 0x17, 0xfc, + 0xf2, 0xa5, 0xab, 0x4c, 0x2e, 0x69, 0xcb, 0x82, 0x5f, 0x4c, 0x3c, 0x82, 0xcd, 0x6a, 0xcb, 0x15, + 0xa2, 0xfc, 0x50, 0x54, 0x5e, 0x2e, 0x83, 0x52, 0x48, 0x29, 0x51, 0xcc, 0x50, 0xaa, 0x27, 0xa3, + 0xf3, 0x71, 0xdb, 0x2c, 0x1c, 0xa9, 0x8a, 0xa5, 0x95, 0xab, 0x3e, 0x6f, 0xcd, 0xba, 0x22, 0x7c }, + { 0xf7, 0x5d, 0xb5, 0x20, 0x65, 0xfe, 0xa9, 0xe7, 0x1f, 0x8e, 0xd6, 0xc0, 0xf2, 0x3f, 0x1b, 0x8c, + 0x7a, 0x02, 0x54, 0xd8, 0xa7, 0x0e, 0x6f, 0x68, 0x94, 0x81, 0xff, 0x30, 0x0e, 0x6d, 0x1a, 0x96, + 0x1b, 0x86, 0x07, 0xaa, 0xbf, 0x37, 0xc5, 0x5e, 0x26, 0xa2, 0xdf, 0x0b, 0xd0, 0x7f, 0x94, 0x35, + 0x30, 0xa4, 0x9e, 0x47, 0xaf, 0xad, 0x9c, 0xc9, 0x02, 0x21, 0x55, 0x94, 0x04, 0x13, 0xff, 0x64 }, + { 0x9c, 0x8d, 0x18, 0x63, 0x83, 0xad, 0x01, 0xcc, 0xbb, 0xe6, 0x00, 0xda, 0x15, 0xce, 0xc6, 0x6e, + 0x7a, 0x37, 0x6a, 0x81, 0x44, 0xb3, 0xfc, 0xb7, 0xcd, 0x05, 0xee, 0x4a, 0x6f, 0x29, 0xe4, 0x79, + 0x63, 0x52, 0x7e, 0x14, 0xc9, 0x14, 0x77, 0xa8, 0x19, 0x94, 0x03, 0xc6, 0x51, 0x57, 0xf1, 0xcc, + 0x11, 0x29, 0xde, 0x86, 0x08, 0xfe, 0x41, 0x02, 0x71, 0xb7, 0xbf, 0xd7, 0xe7, 0x83, 0x3e, 0x0c, + 0x9a, 0x59, 0x7e, 0xe8, 0x61, 0x36, 0x56, 0x9a, 0xbf, 0x64, 0xfd, 0xf3, 0xb7, 0xb9, 0x2f, 0x9e, + 0x56, 0x1f, 0x57, 0x45, 0x2e, 0x19, 0x0f, 0x6f, 0x70, 0x01, 0xc2, 0x48, 0x05, 0x23, 0x9b, 0x2f }, + { 0xb5, 0x4e, 0xe7, 0xcc, 0x7b, 0x66, 0x7a, 0xf8, 0xec, 0xcd, 0x1b, 0x0c, 0x0f, 0xec, 0x04, 0x27, + 0xa0, 0x61, 0xfd, 0x12, 0x2d, 0xab, 0xc9, 0xc5, 0x8e, 0xee, 0x36, 0xc2, 0xef, 0x67, 0xd5, 0x87, + 0x95, 0x6c, 0x12, 0xb7, 0x12, 0x81, 0x55, 0xe0, 0x7b, 0xdb, 0x8f, 0x67, 0xea, 0x04, 0x55, 0x91, + 0x9b, 0x50, 0x65, 0x05, 0xc1, 0xf1, 0x0b, 0x04, 0x91, 0x66, 0x3c, 0x32, 0x53, 0x72, 0x01, 0x04, + 0x9a, 0x59, 0x7e, 0xe8, 0x61, 0x36, 0x56, 0x9a, 0xbf, 0x64, 0xfd, 0xf3, 0xb7, 0xb9, 0x2f, 0x9e, + 0x56, 0x1f, 0x57, 0x45, 0x2e, 0x19, 0x0f, 0x6f, 0x70, 0x01, 0xc2, 0x48, 0x05, 0x23, 0x9b, 0x2f } }, + { { 0xc8, 0x37, 0x10, 0xdc, 0xdb, 0xfc, 0x51, 0x91, 0xae, 0x37, 0xa4, 0xe0, 0xcf, 0xbb, 0xdd, 0x92, + 0x93, 0x5f, 0x6b, 0xd6, 0x81, 0xbf, 0x9b, 0x24, 0x5e, 0x0d, 0xf1, 0xe4, 0x04, 0x89, 0xd1, 0x1b, + 0xb2, 0x68, 0x56, 0x3a, 0xdc, 0x59, 0xd0, 0x8a, 0x93, 0x37, 0x5d, 0xa5, 0x40, 0x5e, 0xfe, 0xc9, + 0x41, 0x0b, 0x8a, 0x50, 0xd2, 0xa0, 0x94, 0x86, 0xf7, 0x46, 0x3b, 0x7e, 0x1d, 0xea, 0x2b, 0xa8 }, + { 0x1b, 0xe2, 0xe6, 0x48, 0x86, 0xa8, 0x65, 0xfd, 0x2b, 0xae, 0xc7, 0x7d, 0x41, 0xee, 0xb2, 0x80, + 0x33, 0x1c, 0x0a, 0xdc, 0x42, 0xea, 0x99, 0xd0, 0x1f, 0x6d, 0xc8, 0x80, 0x51, 0x70, 0xd4, 0x19, + 0xae, 0xfc, 0x66, 0x16, 0xa2, 0x53, 0x27, 0x19, 0x7a, 0xf2, 0x9a, 0x25, 0x0c, 0x39, 0x8c, 0xbf, + 0xe7, 0xa3, 0x7a, 0xd6, 0xa3, 0x43, 0x62, 0xd2, 0x4a, 0xc2, 0xf1, 0x96, 0x7e, 0xe3, 0x83, 0x13 }, + { 0xf5, 0xb1, 0x2a, 0xc5, 0x4d, 0xcc, 0xdf, 0x56, 0xde, 0x92, 0x96, 0x46, 0x03, 0x11, 0xfc, 0xa0, + 0xbc, 0xa2, 0x22, 0xf7, 0x25, 0x74, 0x2a, 0x1f, 0x27, 0x34, 0x18, 0xe8, 0x06, 0xa4, 0x77, 0x26, + 0x1a, 0x51, 0x5e, 0xfb, 0x77, 0xbc, 0x55, 0xb1, 0xf8, 0xa5, 0x19, 0x23, 0x00, 0x97, 0xf7, 0xbb, + 0xe4, 0xcd, 0x41, 0x9e, 0xd9, 0x5e, 0x0c, 0x6b, 0x1b, 0x8a, 0xba, 0x52, 0x93, 0xbe, 0x2c, 0xf3 }, + { 0xb3, 0x02, 0xeb, 0x44, 0x3c, 0x05, 0xae, 0x9c, 0x94, 0xa9, 0x1f, 0x72, 0x41, 0xbc, 0x81, 0x66, + 0x5f, 0x50, 0xc0, 0x57, 0xb4, 0x44, 0xf0, 0xe1, 0x2a, 0xa9, 0x88, 0x69, 0xa6, 0x1c, 0x05, 0x85, + 0xda, 0xc7, 0xb2, 0xe1, 0x8c, 0x2f, 0x7c, 0x49, 0x37, 0xa2, 0xf2, 0x56, 0xab, 0x12, 0x9f, 0x12, + 0x4b, 0x1b, 0x73, 0x75, 0x3f, 0x30, 0x0f, 0x40, 0xf1, 0xf9, 0x1d, 0xa7, 0x2c, 0x98, 0x8c, 0x91 }, + { 0xcb, 0xd3, 0x39, 0x60, 0x56, 0xe3, 0xbd, 0x65, 0x86, 0x1a, 0x58, 0x40, 0xc0, 0xa4, 0xc4, 0x8b, + 0xe5, 0xf7, 0x49, 0x0a, 0xf2, 0x09, 0x51, 0x32, 0x6e, 0x06, 0x5a, 0x27, 0x19, 0x78, 0x2e, 0x3a, + 0x04, 0xf9, 0x34, 0x80, 0x49, 0x39, 0x93, 0xcd, 0x89, 0x67, 0x7b, 0xc0, 0x8d, 0x9d, 0x8d, 0x4c, + 0x83, 0x20, 0x80, 0xfc, 0x00, 0xf2, 0x8a, 0x8f, 0xa4, 0x4d, 0x8e, 0x8f, 0x58, 0x51, 0x5b, 0x71 }, + { 0x71, 0x3f, 0x90, 0x41, 0xb8, 0x74, 0xbc, 0x7a, 0x85, 0xf5, 0xab, 0xca, 0x7e, 0xf2, 0x70, 0x41, + 0xbc, 0x36, 0xb5, 0xc3, 0x4e, 0xf1, 0x2b, 0x17, 0x35, 0x40, 0xdb, 0x3c, 0xdb, 0xd2, 0xec, 0x0b, + 0x99, 0xc1, 0x43, 0x17, 0xad, 0x38, 0x45, 0x2d, 0x07, 0x31, 0xd7, 0xb6, 0x95, 0x1c, 0x89, 0x25, + 0xe4, 0x89, 0x97, 0xd3, 0xcf, 0x11, 0x2f, 0x63, 0x31, 0x51, 0xa2, 0x18, 0xfc, 0x12, 0x04, 0x0a, + 0xb0, 0x33, 0xce, 0x0b, 0x57, 0xc0, 0x8c, 0x58, 0x25, 0xf8, 0x9b, 0x50, 0x22, 0x1c, 0x5c, 0x7b, + 0x02, 0xc7, 0xed, 0xfc, 0x98, 0x8b, 0xbd, 0xd2, 0x4e, 0xfc, 0x78, 0x91, 0x7f, 0x4c, 0x99, 0x24 }, + { 0xfc, 0x46, 0xe4, 0x85, 0x0c, 0x52, 0x14, 0xf8, 0x8a, 0xa4, 0x97, 0x17, 0x10, 0xb2, 0x93, 0xef, + 0xa0, 0x66, 0x3c, 0xfd, 0x61, 0x42, 0x24, 0x30, 0x70, 0x4b, 0xfd, 0x0b, 0x86, 0xc8, 0x97, 0xd7, + 0x04, 0xc2, 0xa6, 0x61, 0x41, 0xaf, 0xcc, 0x1d, 0x52, 0xc9, 0xf3, 0xca, 0xe1, 0x90, 0x7c, 0xbd, + 0xce, 0xaf, 0x30, 0xc4, 0xb4, 0x7d, 0x81, 0x7e, 0xbd, 0xe2, 0x09, 0x70, 0x1e, 0x6b, 0xb9, 0x03, + 0xb0, 0x33, 0xce, 0x0b, 0x57, 0xc0, 0x8c, 0x58, 0x25, 0xf8, 0x9b, 0x50, 0x22, 0x1c, 0x5c, 0x7b, + 0x02, 0xc7, 0xed, 0xfc, 0x98, 0x8b, 0xbd, 0xd2, 0x4e, 0xfc, 0x78, 0x91, 0x7f, 0x4c, 0x99, 0x24 } }, + { { 0x5f, 0x01, 0x6d, 0xec, 0x82, 0x02, 0x96, 0x47, 0x74, 0xd9, 0x73, 0x2e, 0x2e, 0x17, 0x00, 0xb6, + 0xe0, 0xa4, 0x13, 0x17, 0xae, 0x7f, 0x85, 0xcb, 0xff, 0xe7, 0x96, 0x99, 0xdb, 0x9f, 0xad, 0x21, + 0x60, 0xd9, 0x12, 0xdc, 0x41, 0x01, 0x33, 0x66, 0x4c, 0x24, 0x8b, 0x25, 0x17, 0xd7, 0x22, 0x14, + 0x12, 0x4d, 0xad, 0x82, 0x9a, 0x85, 0x69, 0x5e, 0x35, 0x10, 0xe0, 0xd7, 0x1a, 0x82, 0x88, 0x14 }, + { 0xab, 0x5f, 0x2c, 0x7d, 0xa2, 0xe5, 0x67, 0x5f, 0xe4, 0x92, 0x03, 0x93, 0xd7, 0x13, 0xa1, 0xfa, + 0x4a, 0xb7, 0x18, 0x4a, 0x8e, 0x8c, 0x78, 0x9a, 0x0c, 0x60, 0x02, 0xe8, 0x2d, 0x50, 0x05, 0x0f, + 0x92, 0xee, 0x9f, 0x81, 0xde, 0x6b, 0x20, 0xe4, 0x9b, 0x17, 0x2e, 0x99, 0x0f, 0x01, 0x31, 0xa7, + 0xc5, 0xc4, 0x53, 0x70, 0xda, 0x03, 0xc6, 0xf7, 0x22, 0x87, 0x98, 0x87, 0x19, 0x36, 0xa6, 0x49 }, + { 0x93, 0xab, 0x22, 0xc4, 0x39, 0x6c, 0x97, 0x80, 0xd2, 0xe2, 0x36, 0xfa, 0x31, 0x74, 0x67, 0xcc, + 0x50, 0x1b, 0x95, 0xbe, 0x77, 0xe0, 0xd1, 0x00, 0x74, 0x04, 0xe1, 0x4d, 0xca, 0x44, 0x35, 0x72, + 0x74, 0x69, 0x82, 0x23, 0x56, 0x9b, 0xcc, 0x34, 0x5a, 0xcb, 0xa2, 0xa3, 0x31, 0x12, 0x4a, 0x84, + 0x4c, 0xe9, 0x37, 0x3a, 0x58, 0xf8, 0x79, 0x65, 0x4a, 0x66, 0x79, 0x82, 0xf4, 0x5d, 0x75, 0xc3 }, + { 0x2d, 0x5d, 0xac, 0x4f, 0xb5, 0x00, 0x68, 0x3b, 0x5f, 0x2e, 0xdd, 0xcb, 0x14, 0x4a, 0x7f, 0xad, + 0x12, 0x45, 0x91, 0xd1, 0x84, 0xd8, 0x14, 0xff, 0xcb, 0x64, 0x43, 0x6d, 0x65, 0xe7, 0x19, 0x68, + 0x2b, 0x5e, 0x53, 0x05, 0x74, 0x66, 0xed, 0xac, 0x2f, 0x5a, 0x8f, 0x70, 0x96, 0xab, 0x29, 0xf3, + 0x9a, 0x59, 0xa2, 0xe2, 0xef, 0xd3, 0xc9, 0xd7, 0x53, 0xf8, 0xf5, 0xa3, 0xd6, 0xf4, 0x34, 0xf8 }, + { 0x1d, 0x14, 0xf3, 0xfd, 0xb0, 0x66, 0x20, 0xff, 0xfc, 0x79, 0x47, 0xc7, 0x4c, 0xe9, 0x45, 0x67, + 0xf5, 0x97, 0x14, 0xea, 0x7c, 0x63, 0xc5, 0x3f, 0x0b, 0x46, 0xe0, 0x88, 0xd6, 0x9b, 0x67, 0x71, + 0xba, 0xa6, 0x15, 0x28, 0x94, 0x54, 0x83, 0x68, 0x00, 0x3a, 0x33, 0xa6, 0x1a, 0x05, 0x6a, 0x68, + 0x72, 0x98, 0x48, 0x71, 0xea, 0x5b, 0x47, 0xf5, 0x80, 0x46, 0xa9, 0x57, 0x84, 0xec, 0xad, 0xfc }, + { 0xa3, 0x1d, 0x87, 0xd3, 0x28, 0x62, 0xc6, 0xf7, 0xdb, 0xfb, 0xfa, 0xfc, 0xf3, 0x27, 0x5c, 0x31, + 0xd3, 0x32, 0x26, 0x0e, 0x0f, 0x41, 0x49, 0xec, 0x05, 0x16, 0xf7, 0xa5, 0x63, 0xb3, 0xbc, 0xe5, + 0x0d, 0x1e, 0x6f, 0x97, 0x4f, 0x68, 0x40, 0xc0, 0xd4, 0x6c, 0x4f, 0x9e, 0x25, 0xd0, 0xab, 0x8d, + 0x2a, 0xb9, 0x3e, 0x06, 0x4d, 0x9d, 0x3d, 0x2d, 0x79, 0x8d, 0x93, 0xdc, 0xfc, 0x6f, 0x0b, 0x04, + 0x48, 0x7c, 0x19, 0x5c, 0xa9, 0xc8, 0x44, 0xe5, 0xf6, 0x4f, 0x51, 0xd8, 0x72, 0x63, 0x41, 0xda, + 0x62, 0xac, 0x78, 0x73, 0xb3, 0x3e, 0xc8, 0xb2, 0xf1, 0x3f, 0x89, 0xf2, 0x0e, 0x95, 0xdf, 0xed }, + { 0xfd, 0x69, 0xb1, 0x9a, 0xdb, 0xae, 0x95, 0x87, 0xe2, 0xc6, 0x8a, 0x97, 0x0c, 0xee, 0xc4, 0x22, + 0x60, 0x4e, 0x96, 0xa9, 0x72, 0xb9, 0x6f, 0x86, 0x97, 0xa8, 0xdf, 0x83, 0xc5, 0x18, 0x18, 0x6e, + 0xc9, 0x43, 0x30, 0x7e, 0x5b, 0xcf, 0x37, 0x0f, 0xc1, 0xd7, 0xe5, 0xab, 0xb1, 0x31, 0xe0, 0x97, + 0xc7, 0x53, 0xb7, 0xfd, 0xd7, 0xdf, 0x00, 0x43, 0x0e, 0x41, 0x62, 0x80, 0x0b, 0xe3, 0xe0, 0x06, + 0x48, 0x7c, 0x19, 0x5c, 0xa9, 0xc8, 0x44, 0xe5, 0xf6, 0x4f, 0x51, 0xd8, 0x72, 0x63, 0x41, 0xda, + 0x62, 0xac, 0x78, 0x73, 0xb3, 0x3e, 0xc8, 0xb2, 0xf1, 0x3f, 0x89, 0xf2, 0x0e, 0x95, 0xdf, 0xed } }, + { { 0x98, 0x29, 0xf7, 0x57, 0xfd, 0xbd, 0x44, 0x3f, 0xd9, 0x90, 0x98, 0x19, 0x97, 0xf2, 0x60, 0x27, + 0xfd, 0x08, 0xfc, 0x8a, 0xc6, 0xaf, 0x87, 0x22, 0x7f, 0x74, 0x4a, 0x80, 0xaf, 0x72, 0x00, 0x01, + 0x70, 0x9b, 0x47, 0x2a, 0xd2, 0x8e, 0x41, 0x0a, 0xea, 0x6a, 0xdf, 0xb7, 0x61, 0x54, 0x89, 0x5e, + 0x01, 0x9f, 0x76, 0x64, 0x29, 0xee, 0x8d, 0x85, 0x20, 0xff, 0x30, 0x58, 0xc2, 0xa3, 0x2a, 0x56 }, + { 0xea, 0x69, 0x8e, 0x6b, 0x8e, 0xdd, 0x55, 0x22, 0x45, 0x61, 0xd4, 0x92, 0x66, 0x8e, 0x96, 0xaf, + 0x7e, 0x40, 0x28, 0x72, 0xc4, 0x46, 0xe7, 0x88, 0xd4, 0x6c, 0x74, 0xb7, 0x48, 0x7f, 0xe8, 0xe1, + 0x5e, 0xa5, 0x85, 0x62, 0x8f, 0xd6, 0xfc, 0x27, 0x0a, 0xb2, 0x4b, 0x38, 0x94, 0x59, 0x52, 0x0d, + 0x6a, 0x4d, 0xe5, 0x61, 0xce, 0x0d, 0x44, 0x03, 0xa6, 0x2a, 0xc2, 0xd4, 0xd4, 0xe2, 0x71, 0xe3 }, + { 0x40, 0xf0, 0x82, 0xf0, 0x8d, 0xaa, 0xad, 0xa9, 0x9f, 0x9b, 0x85, 0x02, 0xcf, 0x57, 0x15, 0x41, + 0x13, 0x59, 0xf2, 0xba, 0xdd, 0xbf, 0x93, 0xe5, 0x40, 0x2e, 0xaf, 0xdd, 0x43, 0x52, 0xc8, 0x7f, + 0x40, 0xad, 0x91, 0x5b, 0x58, 0xd1, 0xa1, 0xe8, 0x6f, 0x77, 0xc3, 0x41, 0x35, 0x5e, 0xf7, 0x03, + 0xba, 0xe4, 0xed, 0x2c, 0x28, 0x59, 0xd6, 0x48, 0xfe, 0x50, 0xcc, 0xf9, 0x80, 0xd1, 0x49, 0xd1 }, + { 0xd7, 0xa5, 0xd9, 0x13, 0xdf, 0x7d, 0xf6, 0xc6, 0x25, 0x0f, 0x52, 0xc2, 0x57, 0x61, 0x20, 0xf2, + 0xf0, 0xdb, 0x47, 0x49, 0x56, 0xaf, 0x89, 0x11, 0xa7, 0x8d, 0x09, 0x3a, 0xfe, 0x45, 0x43, 0xef, + 0x9f, 0x0c, 0x42, 0xaf, 0xa8, 0xcc, 0x60, 0x48, 0xc0, 0x1c, 0x7c, 0xbe, 0x01, 0xe2, 0x88, 0xcc, + 0x6c, 0x3e, 0x97, 0x91, 0xf3, 0xd9, 0xb2, 0xb2, 0x09, 0x7e, 0x35, 0xb1, 0x78, 0xb4, 0x03, 0xf6 }, + { 0x08, 0xc4, 0x1a, 0x3a, 0xc3, 0xe3, 0x26, 0xbd, 0x8d, 0xee, 0x5d, 0xf0, 0xba, 0xb6, 0x65, 0xff, + 0x77, 0xc0, 0x99, 0xd1, 0xca, 0xdc, 0xf5, 0x4b, 0x50, 0x50, 0x0a, 0x9e, 0x13, 0x33, 0x76, 0x86, + 0x9b, 0x39, 0x79, 0x78, 0x73, 0x5c, 0x2f, 0x69, 0xa9, 0x9e, 0x0b, 0xeb, 0x11, 0x1e, 0x12, 0xaa, + 0xc1, 0x09, 0x83, 0x0f, 0xca, 0xcb, 0x95, 0x10, 0xde, 0x85, 0xe3, 0x75, 0x62, 0x4a, 0xc2, 0x4c }, + { 0x68, 0x78, 0x6c, 0xce, 0x2f, 0x72, 0x80, 0xfe, 0x83, 0x88, 0x63, 0x37, 0xa7, 0xa1, 0x5a, 0x0b, + 0x84, 0x8a, 0xda, 0x28, 0x84, 0xf1, 0x6a, 0x63, 0x24, 0x1c, 0x72, 0xda, 0x84, 0xee, 0x1d, 0xe0, + 0x77, 0xf0, 0xf6, 0xce, 0x7e, 0x79, 0x0a, 0x55, 0x03, 0x01, 0x13, 0x0f, 0xf7, 0x6b, 0x45, 0xe7, + 0xcb, 0xfd, 0xb0, 0x37, 0x93, 0x4b, 0x40, 0x69, 0xe0, 0x77, 0x67, 0x72, 0x65, 0xee, 0x35, 0x08, + 0x00, 0xc0, 0x07, 0x10, 0xd8, 0x6e, 0x55, 0x83, 0x5a, 0xbc, 0xfa, 0x67, 0x80, 0x8f, 0xfa, 0x21, + 0x3e, 0x56, 0x53, 0x5b, 0xbc, 0x9d, 0xff, 0x16, 0xd9, 0x57, 0xcf, 0x2b, 0x78, 0x06, 0x5a, 0x89 }, + { 0xdf, 0x32, 0x1a, 0x01, 0x84, 0xe5, 0xb8, 0x2c, 0x70, 0x6c, 0xeb, 0xd1, 0xf0, 0xb4, 0x9b, 0x32, + 0xc8, 0xd0, 0x81, 0xc4, 0xea, 0xb2, 0x7c, 0x32, 0x1a, 0x02, 0x61, 0xf2, 0xd9, 0x4d, 0xe5, 0x85, + 0xad, 0xfc, 0xc6, 0x70, 0xee, 0x85, 0x77, 0x07, 0x9b, 0x5d, 0x5f, 0x88, 0xef, 0xb6, 0xd8, 0xdf, + 0x2b, 0xa2, 0x4d, 0x90, 0x11, 0x2d, 0x38, 0x3f, 0xa8, 0x84, 0xf0, 0x76, 0xdd, 0x31, 0xd0, 0x09, + 0x00, 0xc0, 0x07, 0x10, 0xd8, 0x6e, 0x55, 0x83, 0x5a, 0xbc, 0xfa, 0x67, 0x80, 0x8f, 0xfa, 0x21, + 0x3e, 0x56, 0x53, 0x5b, 0xbc, 0x9d, 0xff, 0x16, 0xd9, 0x57, 0xcf, 0x2b, 0x78, 0x06, 0x5a, 0x89 } }, + { { 0x25, 0x87, 0x1e, 0x6f, 0xe8, 0xd0, 0xde, 0x1d, 0xd5, 0xf2, 0xd3, 0x5b, 0xff, 0x9e, 0x67, 0x99, + 0x60, 0xb4, 0x0e, 0xb7, 0x98, 0x1b, 0x2a, 0x3a, 0x9c, 0xec, 0xc1, 0xe1, 0x2e, 0x2b, 0xc0, 0x3e, + 0x3c, 0xfb, 0x64, 0x91, 0x72, 0xc6, 0x7e, 0x57, 0x47, 0x00, 0x97, 0xbf, 0x8e, 0x0e, 0xbf, 0xad, + 0xd9, 0x28, 0x86, 0x7c, 0xfd, 0x41, 0x91, 0xae, 0x2d, 0xee, 0xc0, 0xb2, 0x32, 0x7d, 0x99, 0x7d }, + { 0x63, 0xc1, 0xf9, 0x61, 0x9c, 0x9e, 0x1a, 0xd7, 0xca, 0xa3, 0x71, 0xd6, 0x34, 0x3d, 0xa7, 0x08, + 0x36, 0x0c, 0xec, 0x37, 0x35, 0x94, 0x1a, 0x45, 0xa9, 0xfa, 0xf2, 0xb5, 0x25, 0x92, 0xbf, 0xd1, + 0x1e, 0xca, 0xdd, 0x5a, 0x23, 0xad, 0x9e, 0x45, 0xc3, 0x66, 0xcb, 0x8f, 0xda, 0xa3, 0xd1, 0xe6, + 0x27, 0x38, 0x11, 0x54, 0x67, 0x31, 0x03, 0x64, 0x35, 0xe0, 0x68, 0x0b, 0x93, 0xee, 0x81, 0x17 }, + { 0x8b, 0x01, 0xe9, 0x99, 0x54, 0x54, 0x73, 0x15, 0x0b, 0xac, 0x38, 0x7b, 0xe9, 0xe3, 0x17, 0x4f, + 0x02, 0x3e, 0xe3, 0x8e, 0xda, 0x41, 0xa0, 0x9d, 0x10, 0xe0, 0xda, 0x11, 0xfe, 0xec, 0x2f, 0x42, + 0xe7, 0xc8, 0xb3, 0xde, 0x2f, 0x7b, 0xfd, 0xdf, 0x7c, 0x34, 0x3b, 0x5e, 0xac, 0x22, 0x8c, 0x99, + 0x3d, 0xa1, 0xa9, 0xd9, 0x81, 0xb6, 0x51, 0xc8, 0xaf, 0x3e, 0x75, 0xed, 0x45, 0xcf, 0xf7, 0xb9 }, + { 0xaf, 0xe9, 0x9c, 0x16, 0x4a, 0x8f, 0x3b, 0x0f, 0xef, 0x71, 0x2f, 0xaa, 0x8d, 0x7d, 0xce, 0xed, + 0xea, 0x31, 0x93, 0xaf, 0x2c, 0x75, 0xc6, 0xfa, 0xda, 0x3e, 0xa6, 0xea, 0x2a, 0x3e, 0x7b, 0x72, + 0xb6, 0xf8, 0xd7, 0x9a, 0x88, 0xcb, 0x0b, 0x81, 0x97, 0x24, 0x29, 0x3b, 0x11, 0x23, 0x69, 0xc2, + 0xff, 0x98, 0x39, 0x25, 0x99, 0xae, 0xe1, 0x07, 0x3e, 0x97, 0xde, 0x10, 0x21, 0x23, 0x7a, 0x2d }, + { 0xbe, 0x2f, 0xb9, 0x4c, 0x41, 0x5a, 0x9a, 0xf6, 0xfb, 0xf8, 0x26, 0x9d, 0x81, 0x7f, 0x39, 0x91, + 0xaf, 0x5b, 0xf1, 0xd7, 0x93, 0x0a, 0xdf, 0x18, 0x19, 0x4a, 0x80, 0x74, 0x14, 0x98, 0x2b, 0xf2, + 0x3b, 0x25, 0xc5, 0xe8, 0xfc, 0x07, 0x3f, 0x5d, 0xa1, 0x39, 0x27, 0x4e, 0x1c, 0xd2, 0x7a, 0xfe, + 0x3e, 0x7b, 0x03, 0x35, 0x15, 0x9e, 0x35, 0x2b, 0xd0, 0xbe, 0x67, 0x48, 0x42, 0xdd, 0xa4, 0xdd }, + { 0xbd, 0xcd, 0xd7, 0xbf, 0xb1, 0x0a, 0xdb, 0x9f, 0x85, 0x42, 0xba, 0xf4, 0xc8, 0xff, 0xb0, 0xe1, + 0x9a, 0x18, 0x6d, 0x1a, 0xe0, 0x37, 0xc1, 0xa2, 0xe1, 0x1c, 0x38, 0x55, 0x14, 0xbf, 0x64, 0x67, + 0x84, 0x47, 0xb6, 0x0a, 0xf6, 0x93, 0xf1, 0x10, 0xab, 0x09, 0xf0, 0x60, 0x84, 0xe2, 0x4e, 0x4b, + 0x5e, 0xa2, 0xd2, 0xd1, 0x19, 0x22, 0xd7, 0xc4, 0x85, 0x13, 0x23, 0xa3, 0x6a, 0xb6, 0x75, 0x0f, + 0x43, 0xe6, 0xde, 0x7b, 0x67, 0x2a, 0x73, 0x77, 0x9e, 0xb4, 0x94, 0x6c, 0xc3, 0x9a, 0x67, 0x51, + 0xcf, 0xe9, 0x47, 0x46, 0x0e, 0x3a, 0x12, 0x7d, 0x7c, 0x66, 0x73, 0x6c, 0xd5, 0x4a, 0x21, 0x4d }, + { 0x89, 0x7e, 0xd0, 0xbf, 0x2e, 0x9f, 0x0c, 0xff, 0x6e, 0x56, 0x25, 0x9b, 0x79, 0x99, 0x52, 0x27, + 0xc2, 0x3a, 0xaa, 0xf0, 0x47, 0x6d, 0xed, 0x05, 0xa1, 0xeb, 0x9c, 0x92, 0x28, 0x7f, 0x1b, 0xc8, + 0x1c, 0x57, 0x76, 0xab, 0x05, 0xe3, 0xd3, 0xb7, 0xa3, 0xf5, 0xac, 0xa8, 0x21, 0x33, 0x7c, 0xb7, + 0xe7, 0xc2, 0xd0, 0x25, 0x6f, 0xdf, 0x34, 0xd1, 0xb0, 0x34, 0x41, 0x46, 0x30, 0x9c, 0x76, 0x07, + 0x43, 0xe6, 0xde, 0x7b, 0x67, 0x2a, 0x73, 0x77, 0x9e, 0xb4, 0x94, 0x6c, 0xc3, 0x9a, 0x67, 0x51, + 0xcf, 0xe9, 0x47, 0x46, 0x0e, 0x3a, 0x12, 0x7d, 0x7c, 0x66, 0x73, 0x6c, 0xd5, 0x4a, 0x21, 0x4d } } }; -#define IDENTITY_V0_KNOWN_GOOD_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e" -#define IDENTITY_V1_KNOWN_GOOD_0 "26e83e3b8c:1:bwtgzeejkrkxeiuqyy35srdorynvz3nfrepqwiwedkm55bkhx77vaf6deknmikr2tgvymw3dxnifawo4m5pbfcqbnws6wzxlm7rgrad4xu52fcqg7ebwt4rhao6mjmrbn2bhdcevrlard5k7vropjrsuodoysvwbnjqef3q4fkrjgygddl4tatr5ztkjwt7f:a5vpcmommfyvjiqudkk7sjekscc4zyc3vqqdytkwlix5ahsxgz73ic3a62secgmyum65dok7b5aochdhdlinn3olyyswzy64ubx3pzbtryqsfmxpntxsvj7aqrd6kkrr3gobstl5yzln6bgqkihmhktbqt4vfwfqynkfjmncd4xqodogyxzq" +#define IDENTITY_V0_KNOWN_GOOD_0 \ + "8e4df28b72:0:" \ + "ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d" \ + "4daef6114d78a2d7:" \ + "bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509" \ + "f8441985171ff16e" +#define IDENTITY_V1_KNOWN_GOOD_0 \ + "26e83e3b8c:1:" \ + "bwtgzeejkrkxeiuqyy35srdorynvz3nfrepqwiwedkm55bkhx77vaf6deknmikr2tgvymw3dxnifawo4m5pbfcqbnws6wzxlm7rgrad4xu52fcqg" \ + "7ebwt4rhao6mjmrbn2bhdcevrlard5k7vropjrsuodoysvwbnjqef3q4fkrjgygddl4tatr5ztkjwt7f:" \ + "a5vpcmommfyvjiqudkk7sjekscc4zyc3vqqdytkwlix5ahsxgz73ic3a62secgmyum65dok7b5aochdhdlinn3olyyswzy64ubx3pzbtryqsfmxp" \ + "ntxsvj7aqrd6kkrr3gobstl5yzln6bgqkihmhktbqt4vfwfqynkfjmncd4xqodogyxzq" // -------------------------------------------------------------------------------------------------------------------- @@ -233,63 +1381,67 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = #define ZT_SETSTR(s, v) Utils::scopy((s), sizeof(s), v) // Increments and decrements a counter based on object create/destroy -class LifeCycleTracker -{ -public: - ZT_INLINE LifeCycleTracker() : - cnt(nullptr) - {} +class LifeCycleTracker { + public: + ZT_INLINE LifeCycleTracker() : cnt(nullptr) + { + } - ZT_INLINE LifeCycleTracker(const LifeCycleTracker <c) : - cnt(ltc.cnt) - { if (cnt) ++*cnt; } + ZT_INLINE LifeCycleTracker(const LifeCycleTracker& ltc) : cnt(ltc.cnt) + { + if (cnt) + ++*cnt; + } - explicit ZT_INLINE LifeCycleTracker(long &c) : - cnt(&c) - { ++c; } + explicit ZT_INLINE LifeCycleTracker(long& c) : cnt(&c) + { + ++c; + } - ZT_INLINE ~LifeCycleTracker() - { if (cnt) --*cnt; } + ZT_INLINE ~LifeCycleTracker() + { + if (cnt) + --*cnt; + } - ZT_INLINE LifeCycleTracker &operator=(const LifeCycleTracker <c) - { - if (<c != this) { - if (cnt) --*cnt; - cnt = ltc.cnt; - if (cnt) ++*cnt; - } - return *this; - } + ZT_INLINE LifeCycleTracker& operator=(const LifeCycleTracker& ltc) + { + if (<c != this) { + if (cnt) + --*cnt; + cnt = ltc.cnt; + if (cnt) + ++*cnt; + } + return *this; + } - long *cnt; + long* cnt; }; -static bool ZTT_deepCompareCertificateIdentities(const ZT_Certificate_Identity *const a, const ZT_Certificate_Identity *const b) +static bool +ZTT_deepCompareCertificateIdentities(const ZT_Certificate_Identity* const a, const ZT_Certificate_Identity* const b) { - if (a == nullptr) - return (b == nullptr); - if (((a->identity == nullptr) != (b->identity == nullptr)) || ((a->locator == nullptr) != (b->locator == nullptr))) - return false; - if ((a->identity) && (*reinterpret_cast(a->identity) != *reinterpret_cast(b->identity))) - return false; - return !((a->locator) && (*reinterpret_cast(a->locator) != *reinterpret_cast(b->locator))); + if (a == nullptr) + return (b == nullptr); + if (((a->identity == nullptr) != (b->identity == nullptr)) || ((a->locator == nullptr) != (b->locator == nullptr))) + return false; + if ((a->identity) + && (*reinterpret_cast(a->identity) != *reinterpret_cast(b->identity))) + return false; + return ! ( + (a->locator) + && (*reinterpret_cast(a->locator) != *reinterpret_cast(b->locator))); } -static bool ZTT_deepCompareCertificateName(const ZT_Certificate_Name &a, const ZT_Certificate_Name &b) +static bool ZTT_deepCompareCertificateName(const ZT_Certificate_Name& a, const ZT_Certificate_Name& b) { - return !( - (strcmp(a.serialNo, b.serialNo) != 0) || - (strcmp(a.streetAddress, b.streetAddress) != 0) || - (strcmp(a.organization, b.organization) != 0) || - (strcmp(a.country, b.country) != 0) || - (strcmp(a.commonName, b.commonName) != 0) || - (strcmp(a.email, b.email) != 0) || - (strcmp(a.host, b.host) != 0) || - (strcmp(a.locality, b.locality) != 0) || - (strcmp(a.postalCode, b.postalCode) != 0) || - (strcmp(a.province, b.province) != 0) || - (strcmp(a.unit, b.unit) != 0) || - (strcmp(a.url, b.url) != 0)); + return ! ( + (strcmp(a.serialNo, b.serialNo) != 0) || (strcmp(a.streetAddress, b.streetAddress) != 0) + || (strcmp(a.organization, b.organization) != 0) || (strcmp(a.country, b.country) != 0) + || (strcmp(a.commonName, b.commonName) != 0) || (strcmp(a.email, b.email) != 0) || (strcmp(a.host, b.host) != 0) + || (strcmp(a.locality, b.locality) != 0) || (strcmp(a.postalCode, b.postalCode) != 0) + || (strcmp(a.province, b.province) != 0) || (strcmp(a.unit, b.unit) != 0) || (strcmp(a.url, b.url) != 0)); } // This performs a detailed deep comparison of two certificates to catch any @@ -297,1236 +1449,1333 @@ static bool ZTT_deepCompareCertificateName(const ZT_Certificate_Name &a, const Z // for serial number (hash) equivalency... as the hash is computed from the // decode output! Note that serial number is not compared here as this is // checked by normal == operators. -static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate &b) +static bool ZTT_deepCompareCertificates(const Certificate& a, const Certificate& b) { - if ( - (a.usageFlags != b.usageFlags) || - (a.timestamp != b.timestamp) || - (a.validity[0] != b.validity[0]) || - (a.validity[1] != b.validity[1]) || - (a.subject.timestamp != b.subject.timestamp) || - (a.subject.identityCount != b.subject.identityCount) || - (a.subject.networkCount != b.subject.networkCount) || - (a.subject.updateURLCount != b.subject.updateURLCount) || - (a.subject.uniqueIdSize != b.subject.uniqueIdSize) || - (a.subject.uniqueIdSignatureSize != b.subject.uniqueIdSignatureSize) || - (a.maxPathLength != b.maxPathLength) || - (a.signatureSize != b.signatureSize) - ) - return false; + if ((a.usageFlags != b.usageFlags) || (a.timestamp != b.timestamp) || (a.validity[0] != b.validity[0]) + || (a.validity[1] != b.validity[1]) || (a.subject.timestamp != b.subject.timestamp) + || (a.subject.identityCount != b.subject.identityCount) || (a.subject.networkCount != b.subject.networkCount) + || (a.subject.updateURLCount != b.subject.updateURLCount) || (a.subject.uniqueIdSize != b.subject.uniqueIdSize) + || (a.subject.uniqueIdSignatureSize != b.subject.uniqueIdSignatureSize) || (a.maxPathLength != b.maxPathLength) + || (a.signatureSize != b.signatureSize)) + return false; + if ((memcmp(a.subject.uniqueId, b.subject.uniqueId, a.subject.uniqueIdSize) != 0) + || (memcmp(a.subject.uniqueIdSignature, b.subject.uniqueIdSignature, a.subject.uniqueIdSignatureSize) != 0) + || (memcmp(a.signature, b.signature, a.signatureSize) != 0)) + return false; - if ((memcmp(a.subject.uniqueId, b.subject.uniqueId, a.subject.uniqueIdSize) != 0) || (memcmp(a.subject.uniqueIdSignature, b.subject.uniqueIdSignature, a.subject.uniqueIdSignatureSize) != 0) || (memcmp(a.signature, b.signature, a.signatureSize) != 0)) - return false; + if (! ZTT_deepCompareCertificateName(a.subject.name, b.subject.name)) + return false; - if (!ZTT_deepCompareCertificateName(a.subject.name, b.subject.name)) - return false; + if (memcmp(a.issuer, b.issuer, ZT_CERTIFICATE_HASH_SIZE) != 0) + return false; + if ((a.issuerPublicKeySize != b.issuerPublicKeySize) + || (memcmp(a.issuerPublicKey, b.issuerPublicKey, a.issuerPublicKeySize) != 0)) + return false; - if (memcmp(a.issuer, b.issuer, ZT_CERTIFICATE_HASH_SIZE) != 0) - return false; - if ((a.issuerPublicKeySize != b.issuerPublicKeySize) || (memcmp(a.issuerPublicKey, b.issuerPublicKey, a.issuerPublicKeySize) != 0)) - return false; + if ((a.publicKeySize != b.publicKeySize) || (memcmp(a.publicKey, b.publicKey, a.publicKeySize))) + return false; - if ((a.publicKeySize != b.publicKeySize) || (memcmp(a.publicKey, b.publicKey, a.publicKeySize))) - return false; + for (unsigned int i = 0; i < a.subject.identityCount; ++i) { + if (! ZTT_deepCompareCertificateIdentities(a.subject.identities + i, b.subject.identities + i)) + return false; + } - for (unsigned int i = 0; i < a.subject.identityCount; ++i) { - if (!ZTT_deepCompareCertificateIdentities(a.subject.identities + i, b.subject.identities + i)) - return false; - } + for (unsigned int i = 0; i < a.subject.networkCount; ++i) { + if (a.subject.networks[i].id != b.subject.networks[i].id) + return false; + if (a.subject.networks[i].controller.address != b.subject.networks[i].controller.address) + return false; + if (memcmp( + a.subject.networks[i].controller.hash, + b.subject.networks[i].controller.hash, + ZT_FINGERPRINT_HASH_SIZE) + != 0) + return false; + } - for (unsigned int i = 0; i < a.subject.networkCount; ++i) { - if (a.subject.networks[i].id != b.subject.networks[i].id) - return false; - if (a.subject.networks[i].controller.address != b.subject.networks[i].controller.address) - return false; - if (memcmp(a.subject.networks[i].controller.hash, b.subject.networks[i].controller.hash, ZT_FINGERPRINT_HASH_SIZE) != 0) - return false; - } + for (unsigned int i = 0; i < a.subject.updateURLCount; ++i) { + if ((! a.subject.updateURLs) || (! b.subject.updateURLs)) + return false; + if ((! a.subject.updateURLs[i]) || (! b.subject.updateURLs[i])) + return false; + if (strcmp(a.subject.updateURLs[i], b.subject.updateURLs[i]) != 0) + return false; + } - for (unsigned int i = 0; i < a.subject.updateURLCount; ++i) { - if ((!a.subject.updateURLs) || (!b.subject.updateURLs)) - return false; - if ((!a.subject.updateURLs[i]) || (!b.subject.updateURLs[i])) - return false; - if (strcmp(a.subject.updateURLs[i], b.subject.updateURLs[i]) != 0) - return false; - } - - return true; + return true; } -extern "C" const char *ZTT_general() +extern "C" const char* ZTT_general() { - try { - volatile uint64_t endian = 0; - reinterpret_cast(&endian)[0] = 1; - reinterpret_cast(&endian)[1] = 2; - reinterpret_cast(&endian)[2] = 3; - reinterpret_cast(&endian)[3] = 4; - reinterpret_cast(&endian)[4] = 5; - reinterpret_cast(&endian)[5] = 6; - reinterpret_cast(&endian)[6] = 7; - reinterpret_cast(&endian)[7] = 8; + try { + volatile uint64_t endian = 0; + reinterpret_cast(&endian)[0] = 1; + reinterpret_cast(&endian)[1] = 2; + reinterpret_cast(&endian)[2] = 3; + reinterpret_cast(&endian)[3] = 4; + reinterpret_cast(&endian)[4] = 5; + reinterpret_cast(&endian)[5] = 6; + reinterpret_cast(&endian)[6] = 7; + reinterpret_cast(&endian)[7] = 8; #if __BYTE_ORDER == __LITTLE_ENDIAN - if (*(&endian) != 0x0807060504030201ULL) { - ZT_T_PRINTF("[general] Error: __BYTE_ORDER == __LITTLE_ENDIAN but byte order is actually %.16llx" ZT_EOL_S, endian); - return "__BYTE_ORDER incorrectly defined"; - } + if (*(&endian) != 0x0807060504030201ULL) { + ZT_T_PRINTF( + "[general] Error: __BYTE_ORDER == __LITTLE_ENDIAN but byte order is actually %.16llx" ZT_EOL_S, + endian); + return "__BYTE_ORDER incorrectly defined"; + } #else - if (endian != 0x0102030405060708ULL) { - ZT_T_PRINTF("[general] Error: __BYTE_ORDER == __BIG_ENDIAN but byte order is actually %.16llx" ZT_EOL_S,endian); - return "__BYTE_ORDER incorrectly defined"; - } + if (endian != 0x0102030405060708ULL) { + ZT_T_PRINTF( + "[general] Error: __BYTE_ORDER == __BIG_ENDIAN but byte order is actually %.16llx" ZT_EOL_S, + endian); + return "__BYTE_ORDER incorrectly defined"; + } #endif #ifdef ZT_NO_UNALIGNED_ACCESS - ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access not allowed" ZT_EOL_S,(int)(sizeof(void *) * 8),ZT_ENDIAN_S,endian); + ZT_T_PRINTF( + "[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access not allowed" ZT_EOL_S, + (int)(sizeof(void*) * 8), + ZT_ENDIAN_S, + endian); #else - ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access allowed" ZT_EOL_S, (int)(sizeof(void *) * 8), ZT_ENDIAN_S, endian); + ZT_T_PRINTF( + "[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access allowed" ZT_EOL_S, + (int)(sizeof(void*) * 8), + ZT_ENDIAN_S, + endian); #endif - { - ZT_T_PRINTF("[general] Checking structure sizes, alignment, and packing... "); - if ((uintptr_t)&(InetAddress::LO4.as.sa_in) != (uintptr_t)&(InetAddress::LO4.as.sa_in6)) { - ZT_T_PRINTF("FAILED (&sa_in != &sa_in6)" ZT_EOL_S); - return "&sa_in != &sa_in6"; - } - if ((uintptr_t)&(InetAddress::LO4.as.sa_in6.sin6_family) != (uintptr_t)&(InetAddress::LO4.as.ss.ss_family)) { - ZT_T_PRINTF("FAILED (&sa_in6.sin6_family != &ss.ss_family)" ZT_EOL_S); - return "&sa_in6.sin6_family != &ss.ss_family"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[general] Checking structure sizes, alignment, and packing... "); + if ((uintptr_t) & (InetAddress::LO4.as.sa_in) != (uintptr_t) & (InetAddress::LO4.as.sa_in6)) { + ZT_T_PRINTF("FAILED (&sa_in != &sa_in6)" ZT_EOL_S); + return "&sa_in != &sa_in6"; + } + if ((uintptr_t) & (InetAddress::LO4.as.sa_in6.sin6_family) != (uintptr_t) + & (InetAddress::LO4.as.ss.ss_family)) { + ZT_T_PRINTF("FAILED (&sa_in6.sin6_family != &ss.ss_family)" ZT_EOL_S); + return "&sa_in6.sin6_family != &ss.ss_family"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[general] Sanity checking memory zero and copy functions... "); - for (unsigned long k = 0; k < 1000; ++k) { - uint8_t *tmp = new uint8_t[131072]; - uint8_t *tmp2 = new uint8_t[131072]; - for (unsigned long i = 0; i < 131072; ++i) { - tmp[i] = (uint8_t)i; - tmp2[i] = 0; - } - unsigned long l = ((unsigned long)Utils::random() % 131072) + 1; - Utils::copy(tmp2, tmp, l); - if (memcmp(tmp2, tmp, l) != 0) { - ZT_T_PRINTF("FAILED (copy)" ZT_EOL_S); - return "memory copy"; - } - Utils::zero(tmp2, l); - for (unsigned long i = 0; i < l; ++i) { - if (tmp2[i] != 0) { - ZT_T_PRINTF("FAILED (zero)" ZT_EOL_S); - return "memory zero"; - } - } - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[general] Sanity checking memory zero and copy functions... "); + for (unsigned long k = 0; k < 1000; ++k) { + uint8_t* tmp = new uint8_t[131072]; + uint8_t* tmp2 = new uint8_t[131072]; + for (unsigned long i = 0; i < 131072; ++i) { + tmp[i] = (uint8_t)i; + tmp2[i] = 0; + } + unsigned long l = ((unsigned long)Utils::random() % 131072) + 1; + Utils::copy(tmp2, tmp, l); + if (memcmp(tmp2, tmp, l) != 0) { + ZT_T_PRINTF("FAILED (copy)" ZT_EOL_S); + return "memory copy"; + } + Utils::zero(tmp2, l); + for (unsigned long i = 0; i < l; ++i) { + if (tmp2[i] != 0) { + ZT_T_PRINTF("FAILED (zero)" ZT_EOL_S); + return "memory zero"; + } + } + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } #ifdef ZT_ARCH_X64 - ZT_T_PRINTF("[general] X64 CPUID features: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d vpclmulqdq=%d" ZT_EOL_S, - Utils::CPUID.aes, - Utils::CPUID.avx, - Utils::CPUID.avx2, - Utils::CPUID.avx512f, - Utils::CPUID.fsrm, - Utils::CPUID.rdrand, - Utils::CPUID.sha, - Utils::CPUID.vaes, - Utils::CPUID.vpclmulqdq); + ZT_T_PRINTF( + "[general] X64 CPUID features: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d " + "vpclmulqdq=%d" ZT_EOL_S, + Utils::CPUID.aes, + Utils::CPUID.avx, + Utils::CPUID.avx2, + Utils::CPUID.avx512f, + Utils::CPUID.fsrm, + Utils::CPUID.rdrand, + Utils::CPUID.sha, + Utils::CPUID.vaes, + Utils::CPUID.vpclmulqdq); #endif #ifdef ZT_ARCH_ARM_HAS_NEON - ZT_T_PRINTF("[general] ARM capabilities: aes=%d crc32=%d pmull=%d sha1=%d sha2=%d" ZT_EOL_S, - Utils::ARMCAP.aes, - Utils::ARMCAP.crc32, - Utils::ARMCAP.pmull, - Utils::ARMCAP.sha1, - Utils::ARMCAP.sha2); + ZT_T_PRINTF( + "[general] ARM capabilities: aes=%d crc32=%d pmull=%d sha1=%d sha2=%d" ZT_EOL_S, + Utils::ARMCAP.aes, + Utils::ARMCAP.crc32, + Utils::ARMCAP.pmull, + Utils::ARMCAP.sha1, + Utils::ARMCAP.sha2); #endif - { - ZT_T_PRINTF("[general] Testing Utils::countBits() functions... "); - uint32_t i32 = 0; - for (int i = 0; i <= 32; ++i) { - if ((int)Utils::countBits(i32) != i) { - ZT_T_PRINTF("FAILED (uint32_t)" ZT_EOL_S); - return "Utils::countBits(uint32_t) test failed"; - } - i32 <<= 1U; - i32 |= 1U; - } - uint64_t i64 = 0; - for (int i = 0; i <= 64; ++i) { - if ((int)Utils::countBits(i64) != i) { - ZT_T_PRINTF("FAILED (uint64_t)" ZT_EOL_S); - return "Utils::countBits(uint64_t) test failed"; - } - i64 <<= 1U; - i64 |= 1U; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[general] Testing Utils::countBits() functions... "); + uint32_t i32 = 0; + for (int i = 0; i <= 32; ++i) { + if ((int)Utils::countBits(i32) != i) { + ZT_T_PRINTF("FAILED (uint32_t)" ZT_EOL_S); + return "Utils::countBits(uint32_t) test failed"; + } + i32 <<= 1U; + i32 |= 1U; + } + uint64_t i64 = 0; + for (int i = 0; i <= 64; ++i) { + if ((int)Utils::countBits(i64) != i) { + ZT_T_PRINTF("FAILED (uint64_t)" ZT_EOL_S); + return "Utils::countBits(uint64_t) test failed"; + } + i64 <<= 1U; + i64 |= 1U; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[general] Testing byte order loading, storing, and conversion... "); - uint64_t a = Utils::hton((uint64_t)0x0807060504030201ULL); - uint32_t b = Utils::hton((uint32_t)0x04030201); - uint16_t c = Utils::hton((uint16_t)0x0201); - uint8_t t[8]; - if ( - (reinterpret_cast(&a)[7] != 1) || - (reinterpret_cast(&b)[3] != 1) || - (reinterpret_cast(&c)[1] != 1) || - (Utils::ntoh(a) != 0x0807060504030201ULL) || - (Utils::ntoh(b) != 0x04030201) || - (Utils::ntoh(c) != 0x0201) - ) { - ZT_T_PRINTF("FAILED (hton/ntoh)" ZT_EOL_S); - return "Utils::hton() or ntoh() broken"; - } - if (ZT_CONST_TO_BE_UINT64(0x0102030405060708ULL) != Utils::hton((uint64_t)0x0102030405060708ULL)) { - ZT_T_PRINTF("ZT_CONST_TO_BE_UINT64 macro is not working" ZT_EOL_S); - return "ZT_CONST_TO_BE_UINT64 macro is not working"; - } - if (ZT_CONST_TO_BE_UINT16(0x0102) != Utils::hton((uint16_t)0x0102)) { - ZT_T_PRINTF("ZT_CONST_TO_BE_UINT16 macro is not working" ZT_EOL_S); - return "ZT_CONST_TO_BE_UINT16 macro is not working"; - } + { + ZT_T_PRINTF("[general] Testing byte order loading, storing, and conversion... "); + uint64_t a = Utils::hton((uint64_t)0x0807060504030201ULL); + uint32_t b = Utils::hton((uint32_t)0x04030201); + uint16_t c = Utils::hton((uint16_t)0x0201); + uint8_t t[8]; + if ((reinterpret_cast(&a)[7] != 1) || (reinterpret_cast(&b)[3] != 1) + || (reinterpret_cast(&c)[1] != 1) || (Utils::ntoh(a) != 0x0807060504030201ULL) + || (Utils::ntoh(b) != 0x04030201) || (Utils::ntoh(c) != 0x0201)) { + ZT_T_PRINTF("FAILED (hton/ntoh)" ZT_EOL_S); + return "Utils::hton() or ntoh() broken"; + } + if (ZT_CONST_TO_BE_UINT64(0x0102030405060708ULL) != Utils::hton((uint64_t)0x0102030405060708ULL)) { + ZT_T_PRINTF("ZT_CONST_TO_BE_UINT64 macro is not working" ZT_EOL_S); + return "ZT_CONST_TO_BE_UINT64 macro is not working"; + } + if (ZT_CONST_TO_BE_UINT16(0x0102) != Utils::hton((uint16_t)0x0102)) { + ZT_T_PRINTF("ZT_CONST_TO_BE_UINT16 macro is not working" ZT_EOL_S); + return "ZT_CONST_TO_BE_UINT16 macro is not working"; + } #if __BYTE_ORDER == __LITTLE_ENDIAN - if (Utils::loadMachineEndian< uint64_t >(&a) != 0x0102030405060708ULL) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian< uint32_t >(&b) != 0x01020304) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian< uint16_t >(&c) != 0x0102) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - Utils::zero< sizeof(t) >(t); - Utils::storeMachineEndian< uint64_t >(t, 0x0807060504030201ULL); - if (t[0] != 1) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero< sizeof(t) >(t); - Utils::storeMachineEndian< uint32_t >(t, 0x04030201); - if (t[0] != 1) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero< sizeof(t) >(t); - Utils::storeMachineEndian< uint16_t >(t, 0x0201); - if (t[0] != 1) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } + if (Utils::loadMachineEndian(&a) != 0x0102030405060708ULL) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&b) != 0x01020304) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&c) != 0x0102) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x0807060504030201ULL); + if (t[0] != 1) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x04030201); + if (t[0] != 1) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x0201); + if (t[0] != 1) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } #else - if (Utils::loadMachineEndian(&a) != 0x0807060504030201ULL) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian(&b) != 0x04030201) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian(&c) != 0x0201) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x0807060504030201ULL); - if (t[0] != 8) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x04030201); - if (t[0] != 4) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x0201); - if (t[0] != 2) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } + if (Utils::loadMachineEndian(&a) != 0x0807060504030201ULL) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&b) != 0x04030201) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&c) != 0x0201) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x0807060504030201ULL); + if (t[0] != 8) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x04030201); + if (t[0] != 4) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t, 0x0201); + if (t[0] != 2) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } #endif - ZT_T_PRINTF("OK" ZT_EOL_S); - } - ZT_T_PRINTF("[general] Utils::hash64() samples for 1, 2, int64_max, uint64_max: %.16llx %.16llx %.16llx %.16llx" ZT_EOL_S, Utils::hash64(1), Utils::hash64(2), Utils::hash64(0xffffffffffffffffULL), Utils::hash64(0x7fffffffffffffffULL)); + ZT_T_PRINTF("OK" ZT_EOL_S); + } + ZT_T_PRINTF( + "[general] Utils::hash64() samples for 1, 2, int64_max, uint64_max: %.16llx %.16llx %.16llx " + "%.16llx" ZT_EOL_S, + Utils::hash64(1), + Utils::hash64(2), + Utils::hash64(0xffffffffffffffffULL), + Utils::hash64(0x7fffffffffffffffULL)); - { - // These collisions could *technically* occur but the probability is only 1 / 2^64. - // If this happens something is probably wrong, or else you should be playing the lotto. - ZT_T_PRINTF("[general] Sanity checking random functions... "); - const uint64_t a = Utils::getSecureRandomU64(); - const uint64_t b = Utils::getSecureRandomU64(); - if (a == b) { - ZT_T_PRINTF("FAILED (Utils::getSecureRandomU64() produced duplicate output)" ZT_EOL_S); - return "Utils::getSecureRandomU64() produced duplicate output"; - } - const uint64_t c = Utils::random(); - const uint64_t d = Utils::random(); - if (c == d) { - ZT_T_PRINTF("FAILED (Utils::random() produced duplicate output)" ZT_EOL_S); - return "Utils::random() produced duplicate output"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); + { + // These collisions could *technically* occur but the probability is only 1 / 2^64. + // If this happens something is probably wrong, or else you should be playing the lotto. + ZT_T_PRINTF("[general] Sanity checking random functions... "); + const uint64_t a = Utils::getSecureRandomU64(); + const uint64_t b = Utils::getSecureRandomU64(); + if (a == b) { + ZT_T_PRINTF("FAILED (Utils::getSecureRandomU64() produced duplicate output)" ZT_EOL_S); + return "Utils::getSecureRandomU64() produced duplicate output"; + } + const uint64_t c = Utils::random(); + const uint64_t d = Utils::random(); + if (c == d) { + ZT_T_PRINTF("FAILED (Utils::random() produced duplicate output)" ZT_EOL_S); + return "Utils::random() produced duplicate output"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); - ZT_T_PRINTF("[general] Utils::random() samples: %.16llx %.16llx" ZT_EOL_S, c, d); + ZT_T_PRINTF("[general] Utils::random() samples: %.16llx %.16llx" ZT_EOL_S, c, d); - uint8_t secrand[64]; - Utils::getSecureRandom(secrand, sizeof(secrand)); - char secrands[256]; - Utils::hex(secrand, sizeof(secrand), secrands); - ZT_T_PRINTF("[general] Utils::getSecureRandom() sample: %s" ZT_EOL_S, secrands); - } + uint8_t secrand[64]; + Utils::getSecureRandom(secrand, sizeof(secrand)); + char secrands[256]; + Utils::hex(secrand, sizeof(secrand), secrands); + ZT_T_PRINTF("[general] Utils::getSecureRandom() sample: %s" ZT_EOL_S, secrands); + } - { - ZT_T_PRINTF("[general] Testing FCV (fixed capacity vector)... "); - long cnt = 0; - FCV< LifeCycleTracker, 1024 > test, test2; - for (unsigned int i = 0; i < 512; ++i) - test.push_back(LifeCycleTracker(cnt)); - if (cnt != (long)test.size()) { - ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S, cnt); - return "FCV object life cycle test failed (1)"; - } - test2 = test; - if (cnt != (long)(test.size() + test2.size())) { - ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S, cnt); - return "FCV object life cycle test failed (2)"; - } - test.clear(); - if (cnt != (long)test2.size()) { - ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S, cnt); - return "FCV object life cycle test failed (3)"; - } - for (unsigned int i = 0; i < 512; ++i) - test.push_back(LifeCycleTracker(cnt)); - if (cnt != (long)(test.size() + test2.size())) { - ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S, cnt); - return "FCV object life cycle test failed (4)"; - } - test.clear(); - test2.clear(); - if ((cnt != (long)test.size()) && (cnt != 0)) { - ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S, cnt); - return "FCV object life cycle test failed (5)"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[general] Testing FCV (fixed capacity vector)... "); + long cnt = 0; + FCV test, test2; + for (unsigned int i = 0; i < 512; ++i) + test.push_back(LifeCycleTracker(cnt)); + if (cnt != (long)test.size()) { + ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S, cnt); + return "FCV object life cycle test failed (1)"; + } + test2 = test; + if (cnt != (long)(test.size() + test2.size())) { + ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S, cnt); + return "FCV object life cycle test failed (2)"; + } + test.clear(); + if (cnt != (long)test2.size()) { + ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S, cnt); + return "FCV object life cycle test failed (3)"; + } + for (unsigned int i = 0; i < 512; ++i) + test.push_back(LifeCycleTracker(cnt)); + if (cnt != (long)(test.size() + test2.size())) { + ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S, cnt); + return "FCV object life cycle test failed (4)"; + } + test.clear(); + test2.clear(); + if ((cnt != (long)test.size()) && (cnt != 0)) { + ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S, cnt); + return "FCV object life cycle test failed (5)"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[general] Testing Buf memory pool (basic sanity check)... "); - try { - std::vector< SharedPtr< Buf > > bufs; - Buf::freePool(); - long cnt = Buf::poolAllocated(); - for (int i = 0; i < (ZT_BUF_MAX_POOL_SIZE + 100); ++i) - bufs.push_back(SharedPtr< Buf >(new Buf())); - cnt += ZT_BUF_MAX_POOL_SIZE + 100; - if (Buf::poolAllocated() != cnt) { - ZT_T_PRINTF("FAILED (1)" ZT_EOL_S); - return "Buf memory pool test failed"; - } - bufs.clear(); - if (Buf::poolAllocated() != ZT_BUF_MAX_POOL_SIZE) { - ZT_T_PRINTF("FAILED (2) (%ld)" ZT_EOL_S, Buf::poolAllocated()); - return "Buf memory pool test failed"; - } - Buf::freePool(); - cnt -= ZT_BUF_MAX_POOL_SIZE + 100; - if (Buf::poolAllocated() != cnt) { - ZT_T_PRINTF("FAILED (3)" ZT_EOL_S); - return "Buf memory pool test failed"; - } - } catch (...) { - ZT_T_PRINTF("FAILED (out of memory)" ZT_EOL_S); - return "Buf memory pool test failed: out of memory"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[general] Testing Buf memory pool (basic sanity check)... "); + try { + std::vector > bufs; + Buf::freePool(); + long cnt = Buf::poolAllocated(); + for (int i = 0; i < (ZT_BUF_MAX_POOL_SIZE + 100); ++i) + bufs.push_back(SharedPtr(new Buf())); + cnt += ZT_BUF_MAX_POOL_SIZE + 100; + if (Buf::poolAllocated() != cnt) { + ZT_T_PRINTF("FAILED (1)" ZT_EOL_S); + return "Buf memory pool test failed"; + } + bufs.clear(); + if (Buf::poolAllocated() != ZT_BUF_MAX_POOL_SIZE) { + ZT_T_PRINTF("FAILED (2) (%ld)" ZT_EOL_S, Buf::poolAllocated()); + return "Buf memory pool test failed"; + } + Buf::freePool(); + cnt -= ZT_BUF_MAX_POOL_SIZE + 100; + if (Buf::poolAllocated() != cnt) { + ZT_T_PRINTF("FAILED (3)" ZT_EOL_S); + return "Buf memory pool test failed"; + } + } + catch (...) { + ZT_T_PRINTF("FAILED (out of memory)" ZT_EOL_S); + return "Buf memory pool test failed: out of memory"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[general] Testing Defragmenter... "); - Defragmenter<> defrag; + { + ZT_T_PRINTF("[general] Testing Defragmenter... "); + Defragmenter<> defrag; - const SharedPtr< Path > nullvia; - uint64_t messageId = 0; - int64_t ts = now(); - for (int k = 0; k < 50000; ++k) { - ++messageId; - FCV< Buf::Slice, ZT_MAX_PACKET_FRAGMENTS > message; - FCV< Buf::Slice, ZT_MAX_PACKET_FRAGMENTS > ref; + const SharedPtr nullvia; + uint64_t messageId = 0; + int64_t ts = now(); + for (int k = 0; k < 50000; ++k) { + ++messageId; + FCV message; + FCV ref; - int frags = 1 + (int)(Utils::random() % ZT_MAX_PACKET_FRAGMENTS); - int skip = ((k & 3) == 1) ? -1 : (int)(Utils::random() % frags); - bool complete = false; - message.resize(frags); - ref.resize(frags); + int frags = 1 + (int)(Utils::random() % ZT_MAX_PACKET_FRAGMENTS); + int skip = ((k & 3) == 1) ? -1 : (int)(Utils::random() % frags); + bool complete = false; + message.resize(frags); + ref.resize(frags); - for (int f = 0; f < frags; ++f) { - if (f != skip) { - ref[f].b.set(new Buf()); - ref[f].s = (unsigned int)(Utils::random() % 24); - ref[f].e = ref[f].s + (unsigned int)(Utils::random() % 1000); - for (unsigned int i = ref[f].s; i < ref[f].e; ++i) - ref[f].b->unsafeData[i] = (uint8_t)f; - } - } + for (int f = 0; f < frags; ++f) { + if (f != skip) { + ref[f].b.set(new Buf()); + ref[f].s = (unsigned int)(Utils::random() % 24); + ref[f].e = ref[f].s + (unsigned int)(Utils::random() % 1000); + for (unsigned int i = ref[f].s; i < ref[f].e; ++i) + ref[f].b->unsafeData[i] = (uint8_t)f; + } + } - for (int f = 0; f < frags; ++f) { - if (f != skip) { - if (complete) { - ZT_T_PRINTF("FAILED (message prematurely complete)" ZT_EOL_S); - return "Defragmenter test failed: message prematurely complete"; - } - switch (defrag.assemble(messageId, message, ref[f].b, ref[f].s, ref[f].e - ref[f].s, f, frags, ts++, nullvia)) { - case Defragmenter<>::OK: - break; - case Defragmenter<>::COMPLETE: - complete = true; - break; - case Defragmenter<>::ERR_DUPLICATE_FRAGMENT: - break; - case Defragmenter<>::ERR_INVALID_FRAGMENT: - ZT_T_PRINTF("FAILED (invalid fragment)" ZT_EOL_S); - return "Defragmenter test failed: invalid fragment"; - case Defragmenter<>::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: - break; - case Defragmenter<>::ERR_OUT_OF_MEMORY: - ZT_T_PRINTF("FAILED (out of memory)" ZT_EOL_S); - return "Defragmenter test failed: out of memory"; - } - } - } + for (int f = 0; f < frags; ++f) { + if (f != skip) { + if (complete) { + ZT_T_PRINTF("FAILED (message prematurely complete)" ZT_EOL_S); + return "Defragmenter test failed: message prematurely complete"; + } + switch (defrag.assemble( + messageId, + message, + ref[f].b, + ref[f].s, + ref[f].e - ref[f].s, + f, + frags, + ts++, + nullvia)) { + case Defragmenter<>::OK: + break; + case Defragmenter<>::COMPLETE: + complete = true; + break; + case Defragmenter<>::ERR_DUPLICATE_FRAGMENT: + break; + case Defragmenter<>::ERR_INVALID_FRAGMENT: + ZT_T_PRINTF("FAILED (invalid fragment)" ZT_EOL_S); + return "Defragmenter test failed: invalid fragment"; + case Defragmenter<>::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: + break; + case Defragmenter<>::ERR_OUT_OF_MEMORY: + ZT_T_PRINTF("FAILED (out of memory)" ZT_EOL_S); + return "Defragmenter test failed: out of memory"; + } + } + } - if (skip == -1) { - if (complete) { - for (int f = 0; f < frags; ++f) { - if (!message[f].b) { - ZT_T_PRINTF("FAILED (fragment %d has null buffer)" ZT_EOL_S, f); - return "Defragmenter test failed: fragment has null buffer"; - } - if ((message[f].s != ref[f].s) || (message[f].e != ref[f].e)) { - ZT_T_PRINTF("FAILED (fragment %d size and bounds incorrect (%u:%u, expected %u:%u))" ZT_EOL_S, f, message[f].s, message[f].e, ref[f].s, ref[f].e); - return "Defragmenter test failed: fragment size and bounds incorrect"; - } - for (unsigned int i = message[f].s; i != message[f].e; ++i) { - if (message[f].b->unsafeData[i] != (uint8_t)f) { - ZT_T_PRINTF("FAILED (fragment %d data invalid (raw index %u: %d != %d))" ZT_EOL_S, f, i, (int)message[f].b->unsafeData[i], f); - return "Defragmenter test failed: fragment data invalid"; - } - } - } - } else { - ZT_T_PRINTF("FAILED (message incomplete after all fragments)" ZT_EOL_S); - return "Defragmenter test failed: message incomplete after all fragments"; - } - } else { - if (complete) { - ZT_T_PRINTF("FAILED (message completed without all fragments)" ZT_EOL_S); - return "Defragmenter test failed: message completed without all fragments"; - } - } - } + if (skip == -1) { + if (complete) { + for (int f = 0; f < frags; ++f) { + if (! message[f].b) { + ZT_T_PRINTF("FAILED (fragment %d has null buffer)" ZT_EOL_S, f); + return "Defragmenter test failed: fragment has null buffer"; + } + if ((message[f].s != ref[f].s) || (message[f].e != ref[f].e)) { + ZT_T_PRINTF( + "FAILED (fragment %d size and bounds incorrect (%u:%u, expected %u:%u))" ZT_EOL_S, + f, + message[f].s, + message[f].e, + ref[f].s, + ref[f].e); + return "Defragmenter test failed: fragment size and bounds incorrect"; + } + for (unsigned int i = message[f].s; i != message[f].e; ++i) { + if (message[f].b->unsafeData[i] != (uint8_t)f) { + ZT_T_PRINTF( + "FAILED (fragment %d data invalid (raw index %u: %d != %d))" ZT_EOL_S, + f, + i, + (int)message[f].b->unsafeData[i], + f); + return "Defragmenter test failed: fragment data invalid"; + } + } + } + } + else { + ZT_T_PRINTF("FAILED (message incomplete after all fragments)" ZT_EOL_S); + return "Defragmenter test failed: message incomplete after all fragments"; + } + } + else { + if (complete) { + ZT_T_PRINTF("FAILED (message completed without all fragments)" ZT_EOL_S); + return "Defragmenter test failed: message completed without all fragments"; + } + } + } - Buf::freePool(); - ZT_T_PRINTF("OK (cache remaining: %u)" ZT_EOL_S, defrag.cacheSize()); - } + Buf::freePool(); + ZT_T_PRINTF("OK (cache remaining: %u)" ZT_EOL_S, defrag.cacheSize()); + } - Identity v0id, v1id; - { - char tmp[2048]; + Identity v0id, v1id; + { + char tmp[2048]; - ZT_T_PRINTF("[general] Testing Identity type 0 (C25519)... "); - Identity id; + ZT_T_PRINTF("[general] Testing Identity type 0 (C25519)... "); + Identity id; - if (!id.fromString(IDENTITY_V0_KNOWN_GOOD_0)) { - ZT_T_PRINTF("FAILED (error parsing test identity #1)" ZT_EOL_S); - return "Identity test failed: parse error"; - } - if (!id.locallyValidate()) { - ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); - return "Identity test failed: validation of known-good identity"; - } - v0id = id; + if (! id.fromString(IDENTITY_V0_KNOWN_GOOD_0)) { + ZT_T_PRINTF("FAILED (error parsing test identity #1)" ZT_EOL_S); + return "Identity test failed: parse error"; + } + if (! id.locallyValidate()) { + ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); + return "Identity test failed: validation of known-good identity"; + } + v0id = id; - Utils::getSecureRandom(tmp, sizeof(tmp)); - for (int k = 0; k < 32; ++k) { - uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE]; - ++tmp[0]; - unsigned int sl = id.sign(tmp, sizeof(tmp), sig, sizeof(sig)); - if (!id.verify(tmp, sizeof(tmp), sig, sl)) { - ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S); - return "Identity test failed: sign/verify with type 0"; - } - ++tmp[1]; - if (id.verify(tmp, sizeof(tmp), sig, sl)) { - ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S); - return "Identity test failed: sign/verify with type 0"; - } - } + Utils::getSecureRandom(tmp, sizeof(tmp)); + for (int k = 0; k < 32; ++k) { + uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE]; + ++tmp[0]; + unsigned int sl = id.sign(tmp, sizeof(tmp), sig, sizeof(sig)); + if (! id.verify(tmp, sizeof(tmp), sig, sl)) { + ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S); + return "Identity test failed: sign/verify with type 0"; + } + ++tmp[1]; + if (id.verify(tmp, sizeof(tmp), sig, sl)) { + ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S); + return "Identity test failed: sign/verify with type 0"; + } + } - uint8_t idm[ZT_IDENTITY_MARSHAL_SIZE_MAX]; - int ms = id.marshal(idm, true); - if (ms <= 0) { - ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S); - return "Identity test failed: v0 marshal"; - } - Identity id2; - if (id2.unmarshal(idm, ms) <= 0) { - ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S); - return "Identity test failed: v0 unmarshal"; - } - if (id != id2) { - ZT_T_PRINTF("FAILED (v0 unmarshal %s != %s)" ZT_EOL_S, id.toString(true).c_str(), id2.toString(true).c_str()); - return "Identity test failed: v0 unmarshal !="; - } - ms = id.marshal(idm, false); - if (ms <= 0) { - ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S); - return "Identity test failed: v0 marshal"; - } - if (id2.unmarshal(idm, ms) <= 0) { - ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S); - return "Identity test failed: v0 unmarshal"; - } - ZT_T_PRINTF("(marshalled size: %d bytes) ", ms); + uint8_t idm[ZT_IDENTITY_MARSHAL_SIZE_MAX]; + int ms = id.marshal(idm, true); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S); + return "Identity test failed: v0 marshal"; + } + Identity id2; + if (id2.unmarshal(idm, ms) <= 0) { + ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S); + return "Identity test failed: v0 unmarshal"; + } + if (id != id2) { + ZT_T_PRINTF( + "FAILED (v0 unmarshal %s != %s)" ZT_EOL_S, + id.toString(true).c_str(), + id2.toString(true).c_str()); + return "Identity test failed: v0 unmarshal !="; + } + ms = id.marshal(idm, false); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S); + return "Identity test failed: v0 marshal"; + } + if (id2.unmarshal(idm, ms) <= 0) { + ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S); + return "Identity test failed: v0 unmarshal"; + } + ZT_T_PRINTF("(marshalled size: %d bytes) ", ms); - Utils::scopy(tmp, sizeof(tmp), IDENTITY_V0_KNOWN_GOOD_0); - tmp[0] = '0'; - if (!id.fromString(tmp)) { - ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S); - return "Identity test failed: parse error"; - } - if (id.locallyValidate()) { - ZT_T_PRINTF("FAILED (validation of known-bad identity returned ok)" ZT_EOL_S); - return "Identity test failed: validation of known-bad identity"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); + Utils::scopy(tmp, sizeof(tmp), IDENTITY_V0_KNOWN_GOOD_0); + tmp[0] = '0'; + if (! id.fromString(tmp)) { + ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S); + return "Identity test failed: parse error"; + } + if (id.locallyValidate()) { + ZT_T_PRINTF("FAILED (validation of known-bad identity returned ok)" ZT_EOL_S); + return "Identity test failed: validation of known-bad identity"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); - /* - { - ZT_T_PRINTF("[general] Generated V1 identity: "); - id.generate(Identity::P384); - id.toString(true,tmp); - ZT_T_PRINTF("%s" ZT_EOL_S,tmp); - id.fingerprint().toString(tmp); - ZT_T_PRINTF("[general] Identity fingerprint: %s" ZT_EOL_S,tmp); - } - */ + /* + { + ZT_T_PRINTF("[general] Generated V1 identity: "); + id.generate(Identity::P384); + id.toString(true,tmp); + ZT_T_PRINTF("%s" ZT_EOL_S,tmp); + id.fingerprint().toString(tmp); + ZT_T_PRINTF("[general] Identity fingerprint: %s" ZT_EOL_S,tmp); + } + */ - ZT_T_PRINTF("[general] Testing Identity type 1 (P384)... "); + ZT_T_PRINTF("[general] Testing Identity type 1 (P384)... "); - if (!id.fromString(IDENTITY_V1_KNOWN_GOOD_0)) { - ZT_T_PRINTF("FAILED (error parsing test identity #1)" ZT_EOL_S); - return "Identity test failed: parse error"; - } - if (!id.locallyValidate()) { - ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); - return "Identity test failed: validation of known-good identity"; - } - v1id = id; + if (! id.fromString(IDENTITY_V1_KNOWN_GOOD_0)) { + ZT_T_PRINTF("FAILED (error parsing test identity #1)" ZT_EOL_S); + return "Identity test failed: parse error"; + } + if (! id.locallyValidate()) { + ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); + return "Identity test failed: validation of known-good identity"; + } + v1id = id; - Utils::getSecureRandom(tmp, sizeof(tmp)); - for (int k = 0; k < 32; ++k) { - uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE]; - ++tmp[0]; - unsigned int sl = id.sign(tmp, sizeof(tmp), sig, sizeof(sig)); - if (!id.verify(tmp, sizeof(tmp), sig, sl)) { - ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S); - return "Identity test failed: sign/verify with type 1"; - } - ++tmp[1]; - if (id.verify(tmp, sizeof(tmp), sig, sl)) { - ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S); - return "Identity test failed: sign/verify with type 1"; - } - } + Utils::getSecureRandom(tmp, sizeof(tmp)); + for (int k = 0; k < 32; ++k) { + uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE]; + ++tmp[0]; + unsigned int sl = id.sign(tmp, sizeof(tmp), sig, sizeof(sig)); + if (! id.verify(tmp, sizeof(tmp), sig, sl)) { + ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S); + return "Identity test failed: sign/verify with type 1"; + } + ++tmp[1]; + if (id.verify(tmp, sizeof(tmp), sig, sl)) { + ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S); + return "Identity test failed: sign/verify with type 1"; + } + } - ms = id.marshal(idm, true); - if (ms <= 0) { - ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S); - return "Identity test failed: v1 marshal"; - } - if (id2.unmarshal(idm, ms) <= 0) { - ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S); - return "Identity test failed: v1 unmarshal"; - } - if (id != id2) { - ZT_T_PRINTF("FAILED (v1 unmarshal !=)" ZT_EOL_S); - return "Identity test failed: v1 unmarshal !="; - } - ms = id.marshal(idm, false); - if (ms <= 0) { - ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S); - return "Identity test failed: v1 marshal"; - } - if (id2.unmarshal(idm, ms) <= 0) { - ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S); - return "Identity test failed: v1 unmarshal"; - } - ZT_T_PRINTF("(marshalled size: %d bytes) ", ms); + ms = id.marshal(idm, true); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S); + return "Identity test failed: v1 marshal"; + } + if (id2.unmarshal(idm, ms) <= 0) { + ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S); + return "Identity test failed: v1 unmarshal"; + } + if (id != id2) { + ZT_T_PRINTF("FAILED (v1 unmarshal !=)" ZT_EOL_S); + return "Identity test failed: v1 unmarshal !="; + } + ms = id.marshal(idm, false); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S); + return "Identity test failed: v1 marshal"; + } + if (id2.unmarshal(idm, ms) <= 0) { + ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S); + return "Identity test failed: v1 unmarshal"; + } + ZT_T_PRINTF("(marshalled size: %d bytes) ", ms); - Utils::scopy(tmp, sizeof(tmp), IDENTITY_V1_KNOWN_GOOD_0); - tmp[0] = '0'; - id.fromString(tmp); - if (id.locallyValidate()) { - ZT_T_PRINTF("FAILED (validation of known-bad identity returned ok)" ZT_EOL_S); - return "Identity test failed: validation of known-bad identity"; - } + Utils::scopy(tmp, sizeof(tmp), IDENTITY_V1_KNOWN_GOOD_0); + tmp[0] = '0'; + id.fromString(tmp); + if (id.locallyValidate()) { + ZT_T_PRINTF("FAILED (validation of known-bad identity returned ok)" ZT_EOL_S); + return "Identity test failed: validation of known-bad identity"; + } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[general] Testing Endpoint and Locator... "); - Endpoint ep0(InetAddress::LO4); - Endpoint ep1(InetAddress::LO6); - Locator loc; - loc.add(ep0, Locator::EndpointAttributes::DEFAULT); - loc.add(ep1, Locator::EndpointAttributes::DEFAULT); - loc.sign(now(), v1id); - String locStr(loc.toString()); - //ZT_T_PRINTF("%s %s %s ",locStr.c_str(),loc.endpoints()[0].toString().c_str(),loc.endpoints()[1].toString().c_str()); - Locator loc2; - if ((!loc2.fromString(locStr.c_str())) || (loc2.toString() != locStr)) { - ZT_T_PRINTF("FAILED (fromString)" ZT_EOL_S); - return "FAILED (Locator toString/fromString)"; - } - if (!loc2.verify(v1id)) { - ZT_T_PRINTF("FAILED (verify)" ZT_EOL_S); - return "FAILED (Locator verify)"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } - } catch (std::exception &e) { - ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S, e.what()); - return e.what(); - } catch (...) { - ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: unknown exception" ZT_EOL_S); - return "an unknown exception occurred"; - } - return nullptr; + { + ZT_T_PRINTF("[general] Testing Endpoint and Locator... "); + Endpoint ep0(InetAddress::LO4); + Endpoint ep1(InetAddress::LO6); + Locator loc; + loc.add(ep0, Locator::EndpointAttributes::DEFAULT); + loc.add(ep1, Locator::EndpointAttributes::DEFAULT); + loc.sign(now(), v1id); + String locStr(loc.toString()); + // ZT_T_PRINTF("%s %s %s + // ",locStr.c_str(),loc.endpoints()[0].toString().c_str(),loc.endpoints()[1].toString().c_str()); + Locator loc2; + if ((! loc2.fromString(locStr.c_str())) || (loc2.toString() != locStr)) { + ZT_T_PRINTF("FAILED (fromString)" ZT_EOL_S); + return "FAILED (Locator toString/fromString)"; + } + if (! loc2.verify(v1id)) { + ZT_T_PRINTF("FAILED (verify)" ZT_EOL_S); + return "FAILED (Locator verify)"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } + } + catch (std::exception& e) { + ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S, e.what()); + return e.what(); + } + catch (...) { + ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: unknown exception" ZT_EOL_S); + return "an unknown exception occurred"; + } + return nullptr; } -extern "C" const char *ZTT_crypto() +extern "C" const char* ZTT_crypto() { - try { - { - ZT_T_PRINTF("[crypto] Testing MIMC52... "); - uint8_t challenge[32]; - Utils::zero<32>(challenge); - uint64_t proof = MIMC52::delay(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); - if (!MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { - ZT_T_PRINTF("FAILED (MIMC52 verify)" ZT_EOL_S); - return "MIMC52 failed (verify)"; - } - if (proof != 0x0001bce730224699ULL) { - ZT_T_PRINTF("FAILED (MIMC52 proof not correct)" ZT_EOL_S); - return "MIMC52 failed (proof not correct)"; - } - challenge[0] = 1; - if (MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { - ZT_T_PRINTF("FAILED (MIMC52 verify known-bad)" ZT_EOL_S); - return "MIMC52 failed (verify known-bad)"; - } - ZT_T_PRINTF("OK (%.16llx)" ZT_EOL_S, proof); - } + try { + { + ZT_T_PRINTF("[crypto] Testing MIMC52... "); + uint8_t challenge[32]; + Utils::zero<32>(challenge); + uint64_t proof = MIMC52::delay(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); + if (! MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { + ZT_T_PRINTF("FAILED (MIMC52 verify)" ZT_EOL_S); + return "MIMC52 failed (verify)"; + } + if (proof != 0x0001bce730224699ULL) { + ZT_T_PRINTF("FAILED (MIMC52 proof not correct)" ZT_EOL_S); + return "MIMC52 failed (proof not correct)"; + } + challenge[0] = 1; + if (MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { + ZT_T_PRINTF("FAILED (MIMC52 verify known-bad)" ZT_EOL_S); + return "MIMC52 failed (verify known-bad)"; + } + ZT_T_PRINTF("OK (%.16llx)" ZT_EOL_S, proof); + } - { - ZT_T_PRINTF("[crypto] Testing SHA384 and SHA512... "); - uint8_t h[64]; - SHA512(h, SHA512_TV0_INPUT, strlen(SHA512_TV0_INPUT)); - if (memcmp(h, SHA512_TV0_DIGEST, 64) != 0) { - ZT_T_PRINTF("FAILED (SHA512)" ZT_EOL_S); - return "SHA512 test vector failed"; - } - SHA384(h, SHA512_TV0_INPUT, strlen(SHA512_TV0_INPUT)); - if (memcmp(h, SHA512_TV0_SHA384_DIGEST, 48) != 0) { - ZT_T_PRINTF("FAILED (SHA384)" ZT_EOL_S); - return "SHA384 test vector failed"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[crypto] Testing SHA384 and SHA512... "); + uint8_t h[64]; + SHA512(h, SHA512_TV0_INPUT, strlen(SHA512_TV0_INPUT)); + if (memcmp(h, SHA512_TV0_DIGEST, 64) != 0) { + ZT_T_PRINTF("FAILED (SHA512)" ZT_EOL_S); + return "SHA512 test vector failed"; + } + SHA384(h, SHA512_TV0_INPUT, strlen(SHA512_TV0_INPUT)); + if (memcmp(h, SHA512_TV0_SHA384_DIGEST, 48) != 0) { + ZT_T_PRINTF("FAILED (SHA384)" ZT_EOL_S); + return "SHA384 test vector failed"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t agree0[32], agree1[32], kh[64], sig[96]; - ZT_T_PRINTF("[crypto] Testing C25519/Ed25519... "); - for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { - C25519::agree(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub2, agree0); - C25519::agree(C25519_TEST_VECTORS[t].priv2, C25519_TEST_VECTORS[t].pub1, agree1); - if (memcmp(agree0, agree1, 32) != 0) { - ZT_T_PRINTF("FAILED (keys do not agree, vector %d)" ZT_EOL_S, t); - return "Curve25519 key agreement test failed (a/b does not agree with b/a)"; - } - SHA512(kh, agree0, 32); - if (memcmp(kh, C25519_TEST_VECTORS[t].agreementSha512, 64) != 0) { - ZT_T_PRINTF("FAILED (hash of agreement does not match test vector %d)" ZT_EOL_S, t); - return "Curve25519 key agreement test failed (does not match expected value)"; - } - C25519::sign(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub1, kh, 64, sig); - if (memcmp(sig, C25519_TEST_VECTORS[t].agreementSignedBy1, ZT_C25519_SIGNATURE_LEN) != 0) { - ZT_T_PRINTF("FAILED (signature of agreement by key 1 does not match test vector %d)" ZT_EOL_S, t); - return "Curve25519 signature test failed (signature by key 1 does not match expected value)"; - } - C25519::sign(C25519_TEST_VECTORS[t].priv2, C25519_TEST_VECTORS[t].pub2, kh, 64, sig); - if (memcmp(sig, C25519_TEST_VECTORS[t].agreementSignedBy2, ZT_C25519_SIGNATURE_LEN) != 0) { - ZT_T_PRINTF("FAILED (signature of agreement by key 2 does not match test vector %d)" ZT_EOL_S, t); - return "Curve25519 signature test failed (signature by key 2 does not match expected value)"; - } - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t agree0[32], agree1[32], kh[64], sig[96]; + ZT_T_PRINTF("[crypto] Testing C25519/Ed25519... "); + for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { + C25519::agree(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub2, agree0); + C25519::agree(C25519_TEST_VECTORS[t].priv2, C25519_TEST_VECTORS[t].pub1, agree1); + if (memcmp(agree0, agree1, 32) != 0) { + ZT_T_PRINTF("FAILED (keys do not agree, vector %d)" ZT_EOL_S, t); + return "Curve25519 key agreement test failed (a/b does not agree with b/a)"; + } + SHA512(kh, agree0, 32); + if (memcmp(kh, C25519_TEST_VECTORS[t].agreementSha512, 64) != 0) { + ZT_T_PRINTF("FAILED (hash of agreement does not match test vector %d)" ZT_EOL_S, t); + return "Curve25519 key agreement test failed (does not match expected value)"; + } + C25519::sign(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub1, kh, 64, sig); + if (memcmp(sig, C25519_TEST_VECTORS[t].agreementSignedBy1, ZT_C25519_SIGNATURE_LEN) != 0) { + ZT_T_PRINTF("FAILED (signature of agreement by key 1 does not match test vector %d)" ZT_EOL_S, t); + return "Curve25519 signature test failed (signature by key 1 does not match expected value)"; + } + C25519::sign(C25519_TEST_VECTORS[t].priv2, C25519_TEST_VECTORS[t].pub2, kh, 64, sig); + if (memcmp(sig, C25519_TEST_VECTORS[t].agreementSignedBy2, ZT_C25519_SIGNATURE_LEN) != 0) { + ZT_T_PRINTF("FAILED (signature of agreement by key 2 does not match test vector %d)" ZT_EOL_S, t); + return "Curve25519 signature test failed (signature by key 2 does not match expected value)"; + } + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t key[ZT_ECC384_SHARED_SECRET_SIZE]; - ZT_T_PRINTF("[crypto] Testing ECC384 (NIST P-384 ECDH/ECDSA)... "); - ECC384ECDH(ECC384_TV0_PUBLIC, ECC384_TV0_PRIVATE, key); - if (memcmp(key, ECC384_TV0_DH_SELF_AGREE, ZT_ECC384_SHARED_SECRET_SIZE) != 0) { - ZT_T_PRINTF("FAILED (test vector 0, self-agree)" ZT_EOL_S); - return "ECC384 test vector 0 self-agree failed"; - } - if (!ECC384ECDSAVerify(ECC384_TV0_PUBLIC, ECC384_TV0_PUBLIC, ECC384_TV0_SIG)) { - ZT_T_PRINTF("FAILED (test vector 0, signature check)" ZT_EOL_S); - return "ECC384 test vector 0 signature check failed"; - } - uint8_t msg[ZT_ECC384_SIGNATURE_HASH_SIZE]; - Utils::getSecureRandom(msg, sizeof(msg)); - uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]; - ECC384ECDSASign(ECC384_TV0_PRIVATE, msg, sig); - if (!ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) { - ZT_T_PRINTF("FAILED (test vector 0, sign/verify)" ZT_EOL_S); - return "ECC384 test vector 0 sign/verify failed"; - } - ++msg[0]; - if (ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) { - ZT_T_PRINTF("FAILED (test vector 0, sign/verify (2))" ZT_EOL_S); - return "ECC384 test vector 0 sign/verify failed (2)"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t key[ZT_ECC384_SHARED_SECRET_SIZE]; + ZT_T_PRINTF("[crypto] Testing ECC384 (NIST P-384 ECDH/ECDSA)... "); + ECC384ECDH(ECC384_TV0_PUBLIC, ECC384_TV0_PRIVATE, key); + if (memcmp(key, ECC384_TV0_DH_SELF_AGREE, ZT_ECC384_SHARED_SECRET_SIZE) != 0) { + ZT_T_PRINTF("FAILED (test vector 0, self-agree)" ZT_EOL_S); + return "ECC384 test vector 0 self-agree failed"; + } + if (! ECC384ECDSAVerify(ECC384_TV0_PUBLIC, ECC384_TV0_PUBLIC, ECC384_TV0_SIG)) { + ZT_T_PRINTF("FAILED (test vector 0, signature check)" ZT_EOL_S); + return "ECC384 test vector 0 signature check failed"; + } + uint8_t msg[ZT_ECC384_SIGNATURE_HASH_SIZE]; + Utils::getSecureRandom(msg, sizeof(msg)); + uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]; + ECC384ECDSASign(ECC384_TV0_PRIVATE, msg, sig); + if (! ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) { + ZT_T_PRINTF("FAILED (test vector 0, sign/verify)" ZT_EOL_S); + return "ECC384 test vector 0 sign/verify failed"; + } + ++msg[0]; + if (ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) { + ZT_T_PRINTF("FAILED (test vector 0, sign/verify (2))" ZT_EOL_S); + return "ECC384 test vector 0 sign/verify failed (2)"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t ks[64]; - ZT_T_PRINTF("[crypto] Testing Salsa20... "); - Salsa20 s20; - s20.init(SALSA20_TV0_KEY, SALSA20_TV0_IV); - Utils::zero< sizeof(ks) >(ks); - s20.crypt20(ks, ks, sizeof(ks)); - if (memcmp(ks, SALSA20_TV0_KS, 64) != 0) { - ZT_T_PRINTF("FAILED (Salsa20 test vector)" ZT_EOL_S); - return "Salsa20 test vector failed"; - } - s20.init(SALSA12_TV0_KEY, SALSA12_TV0_IV); - Utils::zero< sizeof(ks) >(ks); - s20.crypt12(ks, ks, sizeof(ks)); - if (memcmp(ks, SALSA12_TV0_KS, 64) != 0) { - ZT_T_PRINTF("FAILED (Salsa12 test vector)" ZT_EOL_S); - return "Salsa12 test vector failed"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t ks[64]; + ZT_T_PRINTF("[crypto] Testing Salsa20... "); + Salsa20 s20; + s20.init(SALSA20_TV0_KEY, SALSA20_TV0_IV); + Utils::zero(ks); + s20.crypt20(ks, ks, sizeof(ks)); + if (memcmp(ks, SALSA20_TV0_KS, 64) != 0) { + ZT_T_PRINTF("FAILED (Salsa20 test vector)" ZT_EOL_S); + return "Salsa20 test vector failed"; + } + s20.init(SALSA12_TV0_KEY, SALSA12_TV0_IV); + Utils::zero(ks); + s20.crypt12(ks, ks, sizeof(ks)); + if (memcmp(ks, SALSA12_TV0_KS, 64) != 0) { + ZT_T_PRINTF("FAILED (Salsa12 test vector)" ZT_EOL_S); + return "Salsa12 test vector failed"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t tag[16]; - ZT_T_PRINTF("[crypto] Testing Poly1305... "); - Poly1305::compute(tag, POLY1305_TV0_INPUT, sizeof(POLY1305_TV0_INPUT), POLY1305_TV0_KEY); - if (memcmp(tag, POLY1305_TV0_TAG, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); - return "poly1305 test vector 0 failed"; - } - Poly1305::compute(tag, POLY1305_TV1_INPUT, sizeof(POLY1305_TV1_INPUT), POLY1305_TV1_KEY); - if (memcmp(tag, POLY1305_TV1_TAG, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); - return "poly1305 test vector 1 failed"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t tag[16]; + ZT_T_PRINTF("[crypto] Testing Poly1305... "); + Poly1305::compute(tag, POLY1305_TV0_INPUT, sizeof(POLY1305_TV0_INPUT), POLY1305_TV0_KEY); + if (memcmp(tag, POLY1305_TV0_TAG, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); + return "poly1305 test vector 0 failed"; + } + Poly1305::compute(tag, POLY1305_TV1_INPUT, sizeof(POLY1305_TV1_INPUT), POLY1305_TV1_KEY); + if (memcmp(tag, POLY1305_TV1_TAG, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); + return "poly1305 test vector 1 failed"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t out[16]; - ZT_T_PRINTF("[crypto] Testing AES (hardware acceleration: %s)... ", AES::accelerated() ? "enabled" : "disabled"); - AES aes(AES_TEST_VECTOR_0_KEY); - aes.encrypt(AES_TEST_VECTOR_0_IN, out); - if (memcmp(AES_TEST_VECTOR_0_OUT, out, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); - return "AES test vector 0 failed"; - } - aes.decrypt(out, out); - if (memcmp(AES_TEST_VECTOR_0_IN, out, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 0 decrypt)" ZT_EOL_S); - return "AES test vector 0 decrypt failed"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t out[16]; + ZT_T_PRINTF( + "[crypto] Testing AES (hardware acceleration: %s)... ", + AES::accelerated() ? "enabled" : "disabled"); + AES aes(AES_TEST_VECTOR_0_KEY); + aes.encrypt(AES_TEST_VECTOR_0_IN, out); + if (memcmp(AES_TEST_VECTOR_0_OUT, out, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); + return "AES test vector 0 failed"; + } + aes.decrypt(out, out); + if (memcmp(AES_TEST_VECTOR_0_IN, out, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 0 decrypt)" ZT_EOL_S); + return "AES test vector 0 decrypt failed"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - ZT_T_PRINTF("[crypto] Testing AES-CTR... "); - { - uint8_t out[64]; - AES aes(AES_CTR_TEST_VECTOR_0_KEY); - AES::CTR ctr(aes); - ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); - ctr.crypt(AES_CTR_TEST_VECTOR_0_IN, 64); - ctr.finish(); - if (memcmp(out, AES_CTR_TEST_VECTOR_0_OUT, 64) != 0) { - ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); - return "AES-CTR test vector 0 failed"; - } - } - { - uint8_t out[777]; - AES aes(AES_CTR_TEST_VECTOR_0_KEY); - AES::CTR ctr(aes); - ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); - for (unsigned int i = 0; i < 777; ++i) - out[i] = (uint8_t)i; - ctr.crypt(out, 777); - ctr.finish(); - if (memcmp(out, AES_CTR_TEST_VECTOR_1_OUT, 777) != 0) { - ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); - return "AES-CTR test vector 1 failed"; - } - } - { - uint8_t out[777]; - AES aes(AES_CTR_TEST_VECTOR_0_KEY); - AES::CTR ctr(aes); - ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); - for (unsigned int i = 0; i < 777; ++i) - out[i] = (uint8_t)i; - ctr.crypt(out, 111); - ctr.crypt(out + 111, 111); - ctr.crypt(out + 222, 222); - ctr.crypt(out + 444, 111); - ctr.crypt(out + 555, 221); - ctr.crypt(out + 776, 1); - ctr.finish(); - if (memcmp(out, AES_CTR_TEST_VECTOR_1_OUT, 777) != 0) { - ZT_T_PRINTF("FAILED (test vector 1, fragmented)" ZT_EOL_S); - return "AES-CTR test vector 1 (fragmented) failed"; - } - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + ZT_T_PRINTF("[crypto] Testing AES-CTR... "); + { + uint8_t out[64]; + AES aes(AES_CTR_TEST_VECTOR_0_KEY); + AES::CTR ctr(aes); + ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); + ctr.crypt(AES_CTR_TEST_VECTOR_0_IN, 64); + ctr.finish(); + if (memcmp(out, AES_CTR_TEST_VECTOR_0_OUT, 64) != 0) { + ZT_T_PRINTF("FAILED (test vector 0)" ZT_EOL_S); + return "AES-CTR test vector 0 failed"; + } + } + { + uint8_t out[777]; + AES aes(AES_CTR_TEST_VECTOR_0_KEY); + AES::CTR ctr(aes); + ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); + for (unsigned int i = 0; i < 777; ++i) + out[i] = (uint8_t)i; + ctr.crypt(out, 777); + ctr.finish(); + if (memcmp(out, AES_CTR_TEST_VECTOR_1_OUT, 777) != 0) { + ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); + return "AES-CTR test vector 1 failed"; + } + } + { + uint8_t out[777]; + AES aes(AES_CTR_TEST_VECTOR_0_KEY); + AES::CTR ctr(aes); + ctr.init(AES_CTR_TEST_VECTOR_0_IV, out); + for (unsigned int i = 0; i < 777; ++i) + out[i] = (uint8_t)i; + ctr.crypt(out, 111); + ctr.crypt(out + 111, 111); + ctr.crypt(out + 222, 222); + ctr.crypt(out + 444, 111); + ctr.crypt(out + 555, 221); + ctr.crypt(out + 776, 1); + ctr.finish(); + if (memcmp(out, AES_CTR_TEST_VECTOR_1_OUT, 777) != 0) { + ZT_T_PRINTF("FAILED (test vector 1, fragmented)" ZT_EOL_S); + return "AES-CTR test vector 1 (fragmented) failed"; + } + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - uint8_t tag[16]; - ZT_T_PRINTF("[crypto] Testing AES-GMAC (hardware acceleration: %s)... ", AES::GMAC::accelerated() ? "enabled" : "disabled"); - { - AES aes(AES_GMAC_VECTOR_0_KEY); - AES::GMAC gmac(aes); - gmac.init(AES_GMAC_VECTOR_0_IV); - gmac.update(AES_GMAC_VECTOR_0_IN, sizeof(AES_GMAC_VECTOR_0_IN)); - gmac.finish(tag); - if (memcmp(tag, AES_GMAC_VECTOR_0_OUT, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 0, "); - for(int i=0;i<16;++i) - ZT_T_PRINTF("%.2x",(unsigned int)AES_GMAC_VECTOR_0_OUT[i]); - ZT_T_PRINTF(" != "); - for(int i=0;i<16;++i) - ZT_T_PRINTF("%.2x",(unsigned int)tag[i]); - ZT_T_PRINTF(")" ZT_EOL_S); - return "AES-GMAC test vector 0 failed"; - } - } - { - AES aes(AES_GMAC_VECTOR_1_KEY); - AES::GMAC gmac(aes); - gmac.init(AES_GMAC_VECTOR_1_IV); - gmac.update(AES_GMAC_VECTOR_1_IN, sizeof(AES_GMAC_VECTOR_1_IN)); - gmac.finish(tag); - if (memcmp(tag, AES_GMAC_VECTOR_1_OUT, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); - return "AES-GMAC test vector 1 failed"; - } - } - { - AES aes(AES_GMAC_VECTOR_2_KEY); - AES::GMAC gmac(aes); - gmac.init(AES_GMAC_VECTOR_2_IV); - gmac.update(AES_GMAC_VECTOR_2_IN, sizeof(AES_GMAC_VECTOR_2_IN)); - gmac.finish(tag); - if (memcmp(tag, AES_GMAC_VECTOR_2_OUT, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 2)" ZT_EOL_S); - return "AES-GMAC test vector 2 failed"; - } - } - { - AES aes(AES_GMAC_VECTOR_2_KEY); - AES::GMAC gmac(aes); - gmac.init(AES_GMAC_VECTOR_2_IV); - gmac.update(AES_GMAC_VECTOR_2_IN, sizeof(AES_GMAC_VECTOR_2_IN) - 117); - gmac.update(AES_GMAC_VECTOR_2_IN + (sizeof(AES_GMAC_VECTOR_2_IN) - 117), 117); - gmac.finish(tag); - if (memcmp(tag, AES_GMAC_VECTOR_2_OUT, 16) != 0) { - ZT_T_PRINTF("FAILED (test vector 2, two fragments)" ZT_EOL_S); - return "AES-GMAC test vector (in two fragments) 2 failed"; - } - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } + { + uint8_t tag[16]; + ZT_T_PRINTF( + "[crypto] Testing AES-GMAC (hardware acceleration: %s)... ", + AES::GMAC::accelerated() ? "enabled" : "disabled"); + { + AES aes(AES_GMAC_VECTOR_0_KEY); + AES::GMAC gmac(aes); + gmac.init(AES_GMAC_VECTOR_0_IV); + gmac.update(AES_GMAC_VECTOR_0_IN, sizeof(AES_GMAC_VECTOR_0_IN)); + gmac.finish(tag); + if (memcmp(tag, AES_GMAC_VECTOR_0_OUT, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 0, "); + for (int i = 0; i < 16; ++i) + ZT_T_PRINTF("%.2x", (unsigned int)AES_GMAC_VECTOR_0_OUT[i]); + ZT_T_PRINTF(" != "); + for (int i = 0; i < 16; ++i) + ZT_T_PRINTF("%.2x", (unsigned int)tag[i]); + ZT_T_PRINTF(")" ZT_EOL_S); + return "AES-GMAC test vector 0 failed"; + } + } + { + AES aes(AES_GMAC_VECTOR_1_KEY); + AES::GMAC gmac(aes); + gmac.init(AES_GMAC_VECTOR_1_IV); + gmac.update(AES_GMAC_VECTOR_1_IN, sizeof(AES_GMAC_VECTOR_1_IN)); + gmac.finish(tag); + if (memcmp(tag, AES_GMAC_VECTOR_1_OUT, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 1)" ZT_EOL_S); + return "AES-GMAC test vector 1 failed"; + } + } + { + AES aes(AES_GMAC_VECTOR_2_KEY); + AES::GMAC gmac(aes); + gmac.init(AES_GMAC_VECTOR_2_IV); + gmac.update(AES_GMAC_VECTOR_2_IN, sizeof(AES_GMAC_VECTOR_2_IN)); + gmac.finish(tag); + if (memcmp(tag, AES_GMAC_VECTOR_2_OUT, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 2)" ZT_EOL_S); + return "AES-GMAC test vector 2 failed"; + } + } + { + AES aes(AES_GMAC_VECTOR_2_KEY); + AES::GMAC gmac(aes); + gmac.init(AES_GMAC_VECTOR_2_IV); + gmac.update(AES_GMAC_VECTOR_2_IN, sizeof(AES_GMAC_VECTOR_2_IN) - 117); + gmac.update(AES_GMAC_VECTOR_2_IN + (sizeof(AES_GMAC_VECTOR_2_IN) - 117), 117); + gmac.finish(tag); + if (memcmp(tag, AES_GMAC_VECTOR_2_OUT, 16) != 0) { + ZT_T_PRINTF("FAILED (test vector 2, two fragments)" ZT_EOL_S); + return "AES-GMAC test vector (in two fragments) 2 failed"; + } + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } - { - char tmp[256]; - uint8_t fakeIssuer[48]; - Utils::getSecureRandom(fakeIssuer, sizeof(fakeIssuer)); + { + char tmp[256]; + uint8_t fakeIssuer[48]; + Utils::getSecureRandom(fakeIssuer, sizeof(fakeIssuer)); - ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S); + ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S); - ZT_T_PRINTF(" Create test identities... "); - Identity testSubjectId; - testSubjectId.generate(Identity::C25519); - ZT_T_PRINTF("OK" ZT_EOL_S); + ZT_T_PRINTF(" Create test identities... "); + Identity testSubjectId; + testSubjectId.generate(Identity::C25519); + ZT_T_PRINTF("OK" ZT_EOL_S); - ZT_T_PRINTF(" Create subject unique ID key pair... "); - uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE]; - int uniqueIdSize = 0, uniqueIdPrivateKeySize = 0; - if (!Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, uniqueId, &uniqueIdSize, uniqueIdPrivate, &uniqueIdPrivateKeySize)) { - ZT_T_PRINTF("FAILED" ZT_EOL_S); - return "Certificate key pair create"; - } - Utils::b32e(uniqueId, uniqueIdSize, tmp, sizeof(tmp)); - ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp); + ZT_T_PRINTF(" Create subject unique ID key pair... "); + uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE]; + int uniqueIdSize = 0, uniqueIdPrivateKeySize = 0; + if (! Certificate::newKeyPair( + ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, + uniqueId, + &uniqueIdSize, + uniqueIdPrivate, + &uniqueIdPrivateKeySize)) { + ZT_T_PRINTF("FAILED" ZT_EOL_S); + return "Certificate key pair create"; + } + Utils::b32e(uniqueId, uniqueIdSize, tmp, sizeof(tmp)); + ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp); - ZT_T_PRINTF(" Create and sign certificate... "); - ScopedPtr< Certificate > cert(new Certificate()); - cert->subject.timestamp = now(); - cert->addSubjectIdentity(testSubjectId); - cert->addSubjectNetwork(12345, testSubjectId.fingerprint()); - cert->addSubjectUpdateUrl("https://www.zerotier.com/"); - ZT_SETSTR(cert->subject.name.serialNo, "serialNo"); - ZT_SETSTR(cert->subject.name.commonName, "commonName"); - ZT_SETSTR(cert->subject.name.country, "country"); - ZT_SETSTR(cert->subject.name.organization, "organization"); - ZT_SETSTR(cert->subject.name.unit, "unit"); - ZT_SETSTR(cert->subject.name.locality, "locality"); - ZT_SETSTR(cert->subject.name.province, "province"); - ZT_SETSTR(cert->subject.name.streetAddress, "streetAddress"); - ZT_SETSTR(cert->subject.name.postalCode, "postalCode"); - ZT_SETSTR(cert->subject.name.email, "email"); - ZT_SETSTR(cert->subject.name.url, "url"); - ZT_SETSTR(cert->subject.name.host, "host"); - cert->timestamp = cert->subject.timestamp; - cert->validity[0] = 0; - cert->validity[1] = 9223372036854775807LL; - uint8_t issuerPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], certPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE]; - int issuerPrivateKeySize = 0, certPrivateKeySize = 0; - Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, cert->issuerPublicKey, (int *)&cert->issuerPublicKeySize, issuerPrivateKey, &issuerPrivateKeySize); - Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, cert->publicKey, (int *)&cert->publicKeySize, certPrivateKey, &certPrivateKeySize); - cert->setSubjectUniqueId(uniqueIdPrivate, uniqueIdPrivateKeySize); - if (!cert->sign(fakeIssuer, issuerPrivateKey, issuerPrivateKeySize)) { - ZT_T_PRINTF("FAILED" ZT_EOL_S); - return "Certificate sign"; - } - Vector< uint8_t > enc(cert->encode()); - ZT_T_PRINTF("OK (%d bytes)" ZT_EOL_S, (int)enc.size()); + ZT_T_PRINTF(" Create and sign certificate... "); + ScopedPtr cert(new Certificate()); + cert->subject.timestamp = now(); + cert->addSubjectIdentity(testSubjectId); + cert->addSubjectNetwork(12345, testSubjectId.fingerprint()); + cert->addSubjectUpdateUrl("https://www.zerotier.com/"); + ZT_SETSTR(cert->subject.name.serialNo, "serialNo"); + ZT_SETSTR(cert->subject.name.commonName, "commonName"); + ZT_SETSTR(cert->subject.name.country, "country"); + ZT_SETSTR(cert->subject.name.organization, "organization"); + ZT_SETSTR(cert->subject.name.unit, "unit"); + ZT_SETSTR(cert->subject.name.locality, "locality"); + ZT_SETSTR(cert->subject.name.province, "province"); + ZT_SETSTR(cert->subject.name.streetAddress, "streetAddress"); + ZT_SETSTR(cert->subject.name.postalCode, "postalCode"); + ZT_SETSTR(cert->subject.name.email, "email"); + ZT_SETSTR(cert->subject.name.url, "url"); + ZT_SETSTR(cert->subject.name.host, "host"); + cert->timestamp = cert->subject.timestamp; + cert->validity[0] = 0; + cert->validity[1] = 9223372036854775807LL; + uint8_t issuerPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], + certPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE]; + int issuerPrivateKeySize = 0, certPrivateKeySize = 0; + Certificate::newKeyPair( + ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, + cert->issuerPublicKey, + (int*)&cert->issuerPublicKeySize, + issuerPrivateKey, + &issuerPrivateKeySize); + Certificate::newKeyPair( + ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, + cert->publicKey, + (int*)&cert->publicKeySize, + certPrivateKey, + &certPrivateKeySize); + cert->setSubjectUniqueId(uniqueIdPrivate, uniqueIdPrivateKeySize); + if (! cert->sign(fakeIssuer, issuerPrivateKey, issuerPrivateKeySize)) { + ZT_T_PRINTF("FAILED" ZT_EOL_S); + return "Certificate sign"; + } + Vector enc(cert->encode()); + ZT_T_PRINTF("OK (%d bytes)" ZT_EOL_S, (int)enc.size()); - ZT_T_PRINTF(" Testing certificate verify... "); - ZT_CertificateError vr = cert->verify(-1, true); - if (vr != ZT_CERTIFICATE_ERROR_NONE) { - ZT_T_PRINTF("FAILED (verify original) (%d)" ZT_EOL_S, (int)vr); - return "Verify original certificate"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); + ZT_T_PRINTF(" Testing certificate verify... "); + ZT_CertificateError vr = cert->verify(-1, true); + if (vr != ZT_CERTIFICATE_ERROR_NONE) { + ZT_T_PRINTF("FAILED (verify original) (%d)" ZT_EOL_S, (int)vr); + return "Verify original certificate"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); - ZT_T_PRINTF(" Test certificate decode from marshaled format... "); - ScopedPtr< Certificate > cert2(new Certificate()); - if (!cert2->decode(enc.data(), (unsigned int)enc.size())) { - ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S); - return "Certificate decode"; - } - if (cert2->verify(-1, true) != ZT_CERTIFICATE_ERROR_NONE) { - ZT_T_PRINTF("FAILED (verify decoded certificate)" ZT_EOL_S); - return "Verify decoded certificate"; - } - if (!ZTT_deepCompareCertificates(*cert, *cert2)) { - ZT_T_PRINTF("FAILED (compare decoded with original)" ZT_EOL_S); - return "Certificate decode and compare"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); + ZT_T_PRINTF(" Test certificate decode from marshaled format... "); + ScopedPtr cert2(new Certificate()); + if (! cert2->decode(enc.data(), (unsigned int)enc.size())) { + ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S); + return "Certificate decode"; + } + if (cert2->verify(-1, true) != ZT_CERTIFICATE_ERROR_NONE) { + ZT_T_PRINTF("FAILED (verify decoded certificate)" ZT_EOL_S); + return "Verify decoded certificate"; + } + if (! ZTT_deepCompareCertificates(*cert, *cert2)) { + ZT_T_PRINTF("FAILED (compare decoded with original)" ZT_EOL_S); + return "Certificate decode and compare"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); - ZT_T_PRINTF(" Test certificate copy/construct... "); - ScopedPtr< Certificate > cert3(new Certificate(*cert2)); - if (!ZTT_deepCompareCertificates(*cert2, *cert3)) { - ZT_T_PRINTF("FAILED (compare copy with original)" ZT_EOL_S); - return "Certificate copy"; - } - ZT_T_PRINTF("OK" ZT_EOL_S); - } - } catch (std::exception &e) { - ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S, e.what()); - return e.what(); - } catch (...) { - ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: unknown exception" ZT_EOL_S); - return "an unknown exception occurred"; - } - return nullptr; + ZT_T_PRINTF(" Test certificate copy/construct... "); + ScopedPtr cert3(new Certificate(*cert2)); + if (! ZTT_deepCompareCertificates(*cert2, *cert3)) { + ZT_T_PRINTF("FAILED (compare copy with original)" ZT_EOL_S); + return "Certificate copy"; + } + ZT_T_PRINTF("OK" ZT_EOL_S); + } + } + catch (std::exception& e) { + ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S, e.what()); + return e.what(); + } + catch (...) { + ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: unknown exception" ZT_EOL_S); + return "an unknown exception occurred"; + } + return nullptr; } -extern "C" const char *ZTT_benchmarkCrypto() +extern "C" const char* ZTT_benchmarkCrypto() { - try { - uint8_t tmp[16384], tag[16]; - Utils::zero< sizeof(tmp) >(tmp); - Utils::zero< sizeof(tag) >(tag); + try { + uint8_t tmp[16384], tag[16]; + Utils::zero(tmp); + Utils::zero(tag); - { - Utils::getSecureRandom(tmp, 32); - ZT_T_PRINTF("[crypto] Benchmarking MIMC52 for %u rounds... ", ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); - int64_t start = now(); - uint64_t proof = MIMC52::delay(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); - int64_t t = now() - start; - ZT_T_PRINTF("%llu ms total, %.8f ms/round, verification: " , t, (double)t / (double)ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); - start = now(); - if (!MIMC52::verify(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { - ZT_T_PRINTF("FAILED" ZT_EOL_S); - return "MIMC52 verify failed"; - } - t = now() - start; - ZT_T_PRINTF("%llu ms, %.4f per second" ZT_EOL_S, t, 1000.0 / (double)t); - } + { + Utils::getSecureRandom(tmp, 32); + ZT_T_PRINTF("[crypto] Benchmarking MIMC52 for %u rounds... ", ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); + int64_t start = now(); + uint64_t proof = MIMC52::delay(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); + int64_t t = now() - start; + ZT_T_PRINTF( + "%llu ms total, %.8f ms/round, verification: ", + t, + (double)t / (double)ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); + start = now(); + if (! MIMC52::verify(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) { + ZT_T_PRINTF("FAILED" ZT_EOL_S); + return "MIMC52 verify failed"; + } + t = now() - start; + ZT_T_PRINTF("%llu ms, %.4f per second" ZT_EOL_S, t, 1000.0 / (double)t); + } - { - ZT_T_PRINTF("[crypto] Benchmarking SHA384... "); - int64_t start = now(); - for (int i = 0; i < 10000; ++i) - SHA384(tmp, tmp, sizeof(tmp)); - int64_t end = now(); - ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 10000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); - ZT_T_PRINTF("[crypto] Benchmarking SHA512... "); - start = now(); - for (int i = 0; i < 10000; ++i) - SHA512(tmp, tmp, sizeof(tmp)); - end = now(); - ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 10000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); - } + { + ZT_T_PRINTF("[crypto] Benchmarking SHA384... "); + int64_t start = now(); + for (int i = 0; i < 10000; ++i) + SHA384(tmp, tmp, sizeof(tmp)); + int64_t end = now(); + ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 10000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); + ZT_T_PRINTF("[crypto] Benchmarking SHA512... "); + start = now(); + for (int i = 0; i < 10000; ++i) + SHA512(tmp, tmp, sizeof(tmp)); + end = now(); + ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 10000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking AES-CTR..."); - AES aes(AES_CTR_TEST_VECTOR_0_KEY); - AES::CTR ctr(aes); - int64_t end, start = now(); - unsigned long reps = 0; - for (;;) { - ctr.init(AES_CTR_TEST_VECTOR_0_IV, tmp); - ctr.crypt(tmp, sizeof(tmp)); - ctr.finish(); - if (unlikely((++reps & 0xfffU) == 0xfffU)) { - end = now(); - if ((end - start) > 4000) - break; - } - } - foo = tmp[0]; // prevent optimization - ZT_T_PRINTF(" %.4f MiB/sec" ZT_EOL_S, ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); + { + ZT_T_PRINTF("[crypto] Benchmarking AES-CTR..."); + AES aes(AES_CTR_TEST_VECTOR_0_KEY); + AES::CTR ctr(aes); + int64_t end, start = now(); + unsigned long reps = 0; + for (;;) { + ctr.init(AES_CTR_TEST_VECTOR_0_IV, tmp); + ctr.crypt(tmp, sizeof(tmp)); + ctr.finish(); + if (unlikely((++reps & 0xfffU) == 0xfffU)) { + end = now(); + if ((end - start) > 4000) + break; + } + } + foo = tmp[0]; // prevent optimization + ZT_T_PRINTF( + " %.4f MiB/sec" ZT_EOL_S, + ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); - ZT_T_PRINTF("[crypto] Benchmarking AES-GMAC..."); - AES::GMAC gmac(aes); - start = now(); - reps = 0; - for (;;) { - gmac.init(tag); - gmac.update(tmp, sizeof(tmp)); - gmac.finish(tag); - if (unlikely((++reps & 0xfffU) == 0xfffU)) { - end = now(); - if ((end - start) > 4000) - break; - } - } - foo = tag[0]; // prevent optimization - ZT_T_PRINTF(" %.4f MiB/sec" ZT_EOL_S, ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); - } + ZT_T_PRINTF("[crypto] Benchmarking AES-GMAC..."); + AES::GMAC gmac(aes); + start = now(); + reps = 0; + for (;;) { + gmac.init(tag); + gmac.update(tmp, sizeof(tmp)); + gmac.finish(tag); + if (unlikely((++reps & 0xfffU) == 0xfffU)) { + end = now(); + if ((end - start) > 4000) + break; + } + } + foo = tag[0]; // prevent optimization + ZT_T_PRINTF( + " %.4f MiB/sec" ZT_EOL_S, + ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking AES-GMAC-SIV..."); - AES k0(AES_CTR_TEST_VECTOR_0_KEY); - AES k1(AES_GMAC_VECTOR_0_KEY); - AES::GMACSIVEncryptor enc(k0, k1); - int64_t end, start = now(); - unsigned long reps = 0; - for (;;) { - enc.init((uint64_t)reps, tmp); - enc.update1(tmp, sizeof(tmp)); - enc.finish1(); - enc.update2(tmp, sizeof(tmp)); - enc.finish2(); - if (unlikely((++reps & 0xfffU) == 0xfffU)) { - end = now(); - if ((end - start) > 4000) - break; - } - } - foo = tmp[0]; // prevent optimization - ZT_T_PRINTF(" %.4f MiB/sec" ZT_EOL_S, ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); - } + { + ZT_T_PRINTF("[crypto] Benchmarking AES-GMAC-SIV..."); + AES k0(AES_CTR_TEST_VECTOR_0_KEY); + AES k1(AES_GMAC_VECTOR_0_KEY); + AES::GMACSIVEncryptor enc(k0, k1); + int64_t end, start = now(); + unsigned long reps = 0; + for (;;) { + enc.init((uint64_t)reps, tmp); + enc.update1(tmp, sizeof(tmp)); + enc.finish1(); + enc.update2(tmp, sizeof(tmp)); + enc.finish2(); + if (unlikely((++reps & 0xfffU) == 0xfffU)) { + end = now(); + if ((end - start) > 4000) + break; + } + } + foo = tmp[0]; // prevent optimization + ZT_T_PRINTF( + " %.4f MiB/sec" ZT_EOL_S, + ((16384.0 * (double)reps) / 1048576.0) / ((double)(end - start) / 1000.0)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking Poly1305... "); - int64_t start = now(); - for (long i = 0; i < 150000; ++i) - Poly1305::compute(tag, tmp, sizeof(tmp), tag); - int64_t end = now(); - foo = tag[0]; // prevent optimization - ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 150000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); - } + { + ZT_T_PRINTF("[crypto] Benchmarking Poly1305... "); + int64_t start = now(); + for (long i = 0; i < 150000; ++i) + Poly1305::compute(tag, tmp, sizeof(tmp), tag); + int64_t end = now(); + foo = tag[0]; // prevent optimization + ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 150000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking Salsa20/12 (using vector acceleration: %s)... ", Salsa20::accelerated() ? "yes" : "no"); - Salsa20 s20(tmp, tag); - int64_t start = now(); - for (long i = 0; i < 150000; ++i) - s20.crypt12(tmp, tmp, sizeof(tmp)); - int64_t end = now(); - foo = tmp[0]; // prevent optimization - ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 150000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); - } + { + ZT_T_PRINTF( + "[crypto] Benchmarking Salsa20/12 (using vector acceleration: %s)... ", + Salsa20::accelerated() ? "yes" : "no"); + Salsa20 s20(tmp, tag); + int64_t start = now(); + for (long i = 0; i < 150000; ++i) + s20.crypt12(tmp, tmp, sizeof(tmp)); + int64_t end = now(); + foo = tmp[0]; // prevent optimization + ZT_T_PRINTF("%.4f MiB/sec" ZT_EOL_S, ((16384.0 * 150000.0) / 1048576.0) / ((double)(end - start) / 1000.0)); + } - { - uint8_t key[ZT_C25519_ECDH_SHARED_SECRET_SIZE]; - ZT_T_PRINTF("[crypto] Benchmarking Curve25519 ECDH... "); - int64_t start = now(); - for (int i = 0; i < 150; ++i) { - for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) - C25519::agree(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub2, key); - foo = key[0]; // prevent optimization - } - } - int64_t end = now(); - ZT_T_PRINTF("%.4f μs/agreement" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(150 * ZT_NUM_C25519_TEST_VECTORS)); - } + { + uint8_t key[ZT_C25519_ECDH_SHARED_SECRET_SIZE]; + ZT_T_PRINTF("[crypto] Benchmarking Curve25519 ECDH... "); + int64_t start = now(); + for (int i = 0; i < 150; ++i) { + for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) + C25519::agree(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub2, key); + foo = key[0]; // prevent optimization + } + } + int64_t end = now(); + ZT_T_PRINTF( + "%.4f μs/agreement" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(150 * ZT_NUM_C25519_TEST_VECTORS)); + } - { - uint8_t sig[ZT_C25519_SIGNATURE_LEN]; - Utils::zero< sizeof(sig) >(sig); - ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature... "); - int64_t start = now(); - for (int i = 0; i < 150; ++i) { - for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) - C25519::sign(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub1, sig, sizeof(sig), sig); - foo = sig[0]; - } - } - int64_t end = now(); - ZT_T_PRINTF("%.4f μs/signature" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(150 * ZT_NUM_C25519_TEST_VECTORS)); - } + { + uint8_t sig[ZT_C25519_SIGNATURE_LEN]; + Utils::zero(sig); + ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature... "); + int64_t start = now(); + for (int i = 0; i < 150; ++i) { + for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) + C25519::sign(C25519_TEST_VECTORS[t].priv1, C25519_TEST_VECTORS[t].pub1, sig, sizeof(sig), sig); + foo = sig[0]; + } + } + int64_t end = now(); + ZT_T_PRINTF( + "%.4f μs/signature" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(150 * ZT_NUM_C25519_TEST_VECTORS)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature verification... "); - int64_t start = now(); - for (int i = 0; i < 15; ++i) { - for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) - if (C25519::verify(C25519_TEST_VECTORS[t].pub1, C25519_TEST_VECTORS[t].agreementSha512, 64, C25519_TEST_VECTORS[t].agreementSignedBy1, 96)) - ++foo; - } - } - int64_t end = now(); - ZT_T_PRINTF("%.4f μs/verify" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(15 * ZT_NUM_C25519_TEST_VECTORS)); - } + { + ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature verification... "); + int64_t start = now(); + for (int i = 0; i < 15; ++i) { + for (int t = 0; t < ZT_NUM_C25519_TEST_VECTORS; ++t) { // NOLINT(modernize-loop-convert) + if (C25519::verify( + C25519_TEST_VECTORS[t].pub1, + C25519_TEST_VECTORS[t].agreementSha512, + 64, + C25519_TEST_VECTORS[t].agreementSignedBy1, + 96)) + ++foo; + } + } + int64_t end = now(); + ZT_T_PRINTF( + "%.4f μs/verify" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(15 * ZT_NUM_C25519_TEST_VECTORS)); + } - { - uint8_t key[48]; - ZT_T_PRINTF("[crypto] Benchmarking ECC384 ECDH... "); - volatile uint8_t *volatile pub = (volatile uint8_t *)ECC384_TV0_PUBLIC; // NOLINT(hicpp-use-auto,modernize-use-auto) - int64_t start = now(); - for (int i = 0; i < 500; ++i) { - ECC384ECDH((const uint8_t *)pub, ECC384_TV0_PRIVATE, key); - foo = key[0]; - } - int64_t end = now(); - ZT_T_PRINTF("%.4f μs/agreement" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); - } + { + uint8_t key[48]; + ZT_T_PRINTF("[crypto] Benchmarking ECC384 ECDH... "); + volatile uint8_t* volatile pub = + (volatile uint8_t*)ECC384_TV0_PUBLIC; // NOLINT(hicpp-use-auto,modernize-use-auto) + int64_t start = now(); + for (int i = 0; i < 500; ++i) { + ECC384ECDH((const uint8_t*)pub, ECC384_TV0_PRIVATE, key); + foo = key[0]; + } + int64_t end = now(); + ZT_T_PRINTF( + "%.4f μs/agreement" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); + } - { - uint8_t sig[96]; - ZT_T_PRINTF("[crypto] Benchmarking ECC384 signature... "); - int64_t start = now(); - for (int i = 0; i < 500; ++i) { - ECC384ECDSASign(ECC384_TV0_PRIVATE, sig, sig); - foo = sig[0]; - } - int64_t end = now(); - ZT_T_PRINTF("%.4f μs/signature" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); - ZT_T_PRINTF("[crypto] Benchmarking ECC384 signature verification... "); - start = now(); - for (int i = 0; i < 500; ++i) { - if (!ECC384ECDSAVerify(ECC384_TV0_PUBLIC, sig, sig)) - ++foo; - } - end = now(); - ZT_T_PRINTF("%.4f μs/verify" ZT_EOL_S, ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); - } + { + uint8_t sig[96]; + ZT_T_PRINTF("[crypto] Benchmarking ECC384 signature... "); + int64_t start = now(); + for (int i = 0; i < 500; ++i) { + ECC384ECDSASign(ECC384_TV0_PRIVATE, sig, sig); + foo = sig[0]; + } + int64_t end = now(); + ZT_T_PRINTF( + "%.4f μs/signature" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); + ZT_T_PRINTF("[crypto] Benchmarking ECC384 signature verification... "); + start = now(); + for (int i = 0; i < 500; ++i) { + if (! ECC384ECDSAVerify(ECC384_TV0_PUBLIC, sig, sig)) + ++foo; + } + end = now(); + ZT_T_PRINTF( + "%.4f μs/verify" ZT_EOL_S, + ((double)(end - start) * 1000.0) / (double)(500 * ZT_NUM_C25519_TEST_VECTORS)); + } - { - ZT_T_PRINTF("[crypto] Benchmarking V0 Identity generation..."); - Identity id; - int64_t start = now(); - for (long i = 0; i < 10; ++i) { - id.generate(Identity::C25519); - foo = (uint8_t)id.address().toInt(); - ZT_T_PRINTF("."); - } - int64_t end = now(); - ZT_T_PRINTF(" %.4f ms/generation (average)" ZT_EOL_S, (double)(end - start) / 10.0); - ZT_T_PRINTF("[crypto] Benchmarking V0 Identity full validation..."); - start = now(); - for (long i = 0; i < 10; ++i) - foo = (uint8_t)id.locallyValidate(); - end = now(); - ZT_T_PRINTF(" %.4f ms/validation" ZT_EOL_S, (double)(end - start) / 10.0); - ZT_T_PRINTF("[crypto] Benchmarking V1 Identity generation..."); - start = now(); - for (long i = 0; i < 10; ++i) { - id.generate(Identity::P384); - foo = (uint8_t)id.address().toInt(); - ZT_T_PRINTF("."); - } - end = now(); - ZT_T_PRINTF(" %.4f ms/generation (average)" ZT_EOL_S, (double)(end - start) / 10.0); - ZT_T_PRINTF("[crypto] Benchmarking V1 Identity full validation... "); - start = now(); - for (long i = 0; i < 100; ++i) - foo = (uint8_t)id.locallyValidate(); - end = now(); - ZT_T_PRINTF("%.4f ms/validation" ZT_EOL_S, (double)(end - start) / 100.0); - } - } catch (std::exception &e) { - ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S, e.what()); - return e.what(); - } catch (...) { - ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: unknown exception" ZT_EOL_S); - return "an unknown exception occurred"; - } - return nullptr; + { + ZT_T_PRINTF("[crypto] Benchmarking V0 Identity generation..."); + Identity id; + int64_t start = now(); + for (long i = 0; i < 10; ++i) { + id.generate(Identity::C25519); + foo = (uint8_t)id.address().toInt(); + ZT_T_PRINTF("."); + } + int64_t end = now(); + ZT_T_PRINTF(" %.4f ms/generation (average)" ZT_EOL_S, (double)(end - start) / 10.0); + ZT_T_PRINTF("[crypto] Benchmarking V0 Identity full validation..."); + start = now(); + for (long i = 0; i < 10; ++i) + foo = (uint8_t)id.locallyValidate(); + end = now(); + ZT_T_PRINTF(" %.4f ms/validation" ZT_EOL_S, (double)(end - start) / 10.0); + ZT_T_PRINTF("[crypto] Benchmarking V1 Identity generation..."); + start = now(); + for (long i = 0; i < 10; ++i) { + id.generate(Identity::P384); + foo = (uint8_t)id.address().toInt(); + ZT_T_PRINTF("."); + } + end = now(); + ZT_T_PRINTF(" %.4f ms/generation (average)" ZT_EOL_S, (double)(end - start) / 10.0); + ZT_T_PRINTF("[crypto] Benchmarking V1 Identity full validation... "); + start = now(); + for (long i = 0; i < 100; ++i) + foo = (uint8_t)id.locallyValidate(); + end = now(); + ZT_T_PRINTF("%.4f ms/validation" ZT_EOL_S, (double)(end - start) / 100.0); + } + } + catch (std::exception& e) { + ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S, e.what()); + return e.what(); + } + catch (...) { + ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: unknown exception" ZT_EOL_S); + return "an unknown exception occurred"; + } + return nullptr; } #ifdef ZT_STANDALONE_TESTS -int main(int argc, char **argv) +int main(int argc, char** argv) { - bool ok = true; - ok &= ZTT_general() == nullptr; - ZT_T_PRINTF(ZT_EOL_S); - ok &= ZTT_crypto() == nullptr; - ok &= ZTT_benchmarkCrypto() == nullptr; - if (!ok) { - ZT_T_PRINTF(ZT_EOL_S "*** AT LEAST ONE TEST FAILED! ***" ZT_EOL_S); - return 1; - } - return 0; + bool ok = true; + ok &= ZTT_general() == nullptr; + ZT_T_PRINTF(ZT_EOL_S); + ok &= ZTT_crypto() == nullptr; + ok &= ZTT_benchmarkCrypto() == nullptr; + if (! ok) { + ZT_T_PRINTF(ZT_EOL_S "*** AT LEAST ONE TEST FAILED! ***" ZT_EOL_S); + return 1; + } + return 0; } #endif -#endif // ZT_ENABLE_TESTS +#endif // ZT_ENABLE_TESTS diff --git a/core/Tests.h b/core/Tests.h index a0c573345..b2f80c3e0 100644 --- a/core/Tests.h +++ b/core/Tests.h @@ -47,7 +47,7 @@ #include #ifndef ZT_T_PRINTF -#define ZT_T_PRINTF(fmt,...) printf((fmt),##__VA_ARGS__),fflush(stdout) +#define ZT_T_PRINTF(fmt, ...) printf((fmt), ##__VA_ARGS__), fflush(stdout) #endif #ifdef __cplusplus @@ -57,7 +57,7 @@ extern "C" { /** * Test platform, compiler behavior, utility functions, and core classes */ -const char *ZTT_general(); +const char* ZTT_general(); /** * Test crypto using test vectors and simple scenarios @@ -65,17 +65,17 @@ const char *ZTT_general(); * This is not an absolutely exhaustive test, just a sanity check to make sure * crypto routines are basically working. */ -const char *ZTT_crypto(); +const char* ZTT_crypto(); /** * Run benchmarks of cryptographic routines and common constructions */ -const char *ZTT_benchmarkCrypto(); +const char* ZTT_benchmarkCrypto(); #ifdef __cplusplus } #endif -#endif // ZT_ENABLE_TESTS +#endif // ZT_ENABLE_TESTS #endif diff --git a/core/TinyMap.hpp b/core/TinyMap.hpp index cfd52f73f..59ec40f05 100644 --- a/core/TinyMap.hpp +++ b/core/TinyMap.hpp @@ -16,14 +16,14 @@ #include "Constants.hpp" #include "Containers.hpp" -#include "SharedPtr.hpp" #include "Network.hpp" +#include "SharedPtr.hpp" #include "Spinlock.hpp" // The number of buckets must be a power of two. #define ZT_TINYMAP_BUCKETS 1024 -#define ZT_TINYMAP_BUCKETS_MASK (ZT_TINYMAP_BUCKETS - 1) +#define ZT_TINYMAP_BUCKETS_MASK (ZT_TINYMAP_BUCKETS - 1) #define ZT_TINYMAP_LOCKED_POINTER (~((uintptr_t)0)) namespace ZeroTier { @@ -36,117 +36,129 @@ namespace ZeroTier { * fast lookup, with lookups sometimes requiring only a few instructions. It * uses a "lock free" (actually pointer-as-spinlock) design. */ -template< typename V > -class TinyMap -{ -private: - typedef Vector< std::pair< uint64_t, V > > EV; +template class TinyMap { + private: + typedef Vector > EV; -public: - ZT_INLINE TinyMap() - {} + public: + ZT_INLINE TinyMap() + { + } - ZT_INLINE ~TinyMap() - { this->clear(); } + ZT_INLINE ~TinyMap() + { + this->clear(); + } - ZT_INLINE void clear() - { - for(unsigned int i=0; i < ZT_TINYMAP_BUCKETS; ++i) { - for(;;) { - const uintptr_t vptr = m_buckets[i].exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); - if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { - if (vptr != 0) - delete reinterpret_cast(vptr); - m_buckets[i].store(0, std::memory_order_release); - break; - } else { - Spinlock::pause(); - } - } - } - } + ZT_INLINE void clear() + { + for (unsigned int i = 0; i < ZT_TINYMAP_BUCKETS; ++i) { + for (;;) { + const uintptr_t vptr = m_buckets[i].exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); + if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { + if (vptr != 0) + delete reinterpret_cast(vptr); + m_buckets[i].store(0, std::memory_order_release); + break; + } + else { + Spinlock::pause(); + } + } + } + } - ZT_INLINE V get(const uint64_t key) noexcept - { - V tmp; - std::atomic &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; - for(;;) { - const uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); - if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { - if (likely(vptr != 0)) { - for(typename EV::const_iterator n(reinterpret_cast(vptr)->begin()); n != reinterpret_cast(vptr)->end(); ++n) { - if (likely(n->first == key)) { - tmp = n->second; - break; - } - } - } - bucket.store(vptr, std::memory_order_release); - return tmp; - } else { - Spinlock::pause(); - } - } - } + ZT_INLINE V get(const uint64_t key) noexcept + { + V tmp; + std::atomic& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; + for (;;) { + const uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); + if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { + if (likely(vptr != 0)) { + for (typename EV::const_iterator n(reinterpret_cast(vptr)->begin()); + n != reinterpret_cast(vptr)->end(); + ++n) { + if (likely(n->first == key)) { + tmp = n->second; + break; + } + } + } + bucket.store(vptr, std::memory_order_release); + return tmp; + } + else { + Spinlock::pause(); + } + } + } - ZT_INLINE void set(const uint64_t key, const V &value) - { - std::atomic &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; - for(;;) { - uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); - if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { - if (vptr == 0) { - vptr = reinterpret_cast(new EV()); - } else { - for (typename EV::iterator n(reinterpret_cast(vptr)->begin()); n != reinterpret_cast(vptr)->end(); ++n) { - if (n->first == key) { - n->second = value; - bucket.store(vptr, std::memory_order_release); - return; - } - } - } - reinterpret_cast(vptr)->push_back(std::pair< uint64_t, V >(key, value)); - bucket.store(vptr, std::memory_order_release); - return; - } else { - Spinlock::pause(); - } - } - } + ZT_INLINE void set(const uint64_t key, const V& value) + { + std::atomic& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; + for (;;) { + uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); + if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { + if (vptr == 0) { + vptr = reinterpret_cast(new EV()); + } + else { + for (typename EV::iterator n(reinterpret_cast(vptr)->begin()); + n != reinterpret_cast(vptr)->end(); + ++n) { + if (n->first == key) { + n->second = value; + bucket.store(vptr, std::memory_order_release); + return; + } + } + } + reinterpret_cast(vptr)->push_back(std::pair(key, value)); + bucket.store(vptr, std::memory_order_release); + return; + } + else { + Spinlock::pause(); + } + } + } - ZT_INLINE void erase(const uint64_t key) - { - std::atomic &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; - for(;;) { - uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); - if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { - if (likely(vptr != 0)) { - for (typename EV::iterator n(reinterpret_cast(vptr)->begin()); n != reinterpret_cast(vptr)->end(); ++n) { - if (n->first == key) { - reinterpret_cast(vptr)->erase(n); - break; - } - } - if (reinterpret_cast(vptr)->empty()) { - delete reinterpret_cast(vptr); - vptr = 0; - } - } - bucket.store(vptr, std::memory_order_release); - return; - } else { - Spinlock::pause(); - } - } - } + ZT_INLINE void erase(const uint64_t key) + { + std::atomic& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; + for (;;) { + uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); + if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { + if (likely(vptr != 0)) { + for (typename EV::iterator n(reinterpret_cast(vptr)->begin()); + n != reinterpret_cast(vptr)->end(); + ++n) { + if (n->first == key) { + reinterpret_cast(vptr)->erase(n); + break; + } + } + if (reinterpret_cast(vptr)->empty()) { + delete reinterpret_cast(vptr); + vptr = 0; + } + } + bucket.store(vptr, std::memory_order_release); + return; + } + else { + Spinlock::pause(); + } + } + } -private: - std::atomic m_buckets[ZT_TINYMAP_BUCKETS]; + private: + std::atomic m_buckets[ZT_TINYMAP_BUCKETS]; }; static_assert((ZT_TINYMAP_BUCKETS % (sizeof(uintptr_t) * 8)) == 0, "ZT_TINYMAP_BUCKETS is not a power of two"); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Topology.cpp b/core/Topology.cpp index e5422f6e5..27122b4af 100644 --- a/core/Topology.cpp +++ b/core/Topology.cpp @@ -12,244 +12,255 @@ /****/ #include "Topology.hpp" + #include "Defaults.hpp" -#include "TrustStore.hpp" #include "Locator.hpp" +#include "TrustStore.hpp" namespace ZeroTier { -Topology::Topology(const Context &ctx, const CallContext &cc) : - m_ctx(ctx) -{} - -SharedPtr< Peer > Topology::add(const CallContext &cc, const SharedPtr< Peer > &peer) +Topology::Topology(const Context& ctx, const CallContext& cc) : m_ctx(ctx) { - RWMutex::Lock _l(m_peers_l); - SharedPtr< Peer > &hp = m_peers[peer->address()]; - if (hp) - return hp; - m_loadCached(cc, peer->address(), hp); - if (hp) - return hp; - hp = peer; - return peer; } -void Topology::allPeers(Vector< SharedPtr< Peer > > &allPeers, Vector< SharedPtr< Peer > > &rootPeers) const +SharedPtr Topology::add(const CallContext& cc, const SharedPtr& peer) { - allPeers.clear(); - { - RWMutex::RLock l(m_peers_l); - allPeers.reserve(m_peers.size()); - for (Map< Address, SharedPtr< Peer > >::const_iterator i(m_peers.begin()); i != m_peers.end(); ++i) - allPeers.push_back(i->second); - } - { - Mutex::Lock l(m_roots_l); - rootPeers = m_roots; - } + RWMutex::Lock _l(m_peers_l); + SharedPtr& hp = m_peers[peer->address()]; + if (hp) + return hp; + m_loadCached(cc, peer->address(), hp); + if (hp) + return hp; + hp = peer; + return peer; } -void Topology::doPeriodicTasks(const CallContext &cc) +void Topology::allPeers(Vector >& allPeers, Vector >& rootPeers) const { - // Get a list of root peer pointer addresses for filtering during peer cleanup. - Vector< uintptr_t > rootLookup; - { - Mutex::Lock l(m_roots_l); - m_rankRoots(); - rootLookup.reserve(m_roots.size()); - for (Vector< SharedPtr< Peer > >::const_iterator r(m_roots.begin()); r != m_roots.end(); ++r) - rootLookup.push_back((uintptr_t)r->ptr()); - } - std::sort(rootLookup.begin(), rootLookup.end()); - - // Cleaning of peers and paths uses a two pass method to avoid write locking - // m_peers or m_paths for any significant amount of time. This avoids pauses - // on nodes with large numbers of peers or paths. - { - Vector< Address > toDelete; - { - RWMutex::RLock l1(m_peers_l); - for (Map< Address, SharedPtr< Peer > >::iterator i(m_peers.begin()); i != m_peers.end(); ++i) { - // TODO: also delete if the peer has not exchanged meaningful communication in a while, such as a network frame or non-trivial control packet. - if (((cc.ticks - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (!std::binary_search(rootLookup.begin(), rootLookup.end(), reinterpret_cast(i->second.ptr())))) - toDelete.push_back(i->first); - } - } - if (!toDelete.empty()) { - ZT_SPEW("garbage collecting %u offline or stale peer objects", (unsigned int)toDelete.size()); - for (Vector< Address >::iterator i(toDelete.begin()); i != toDelete.end(); ++i) { - SharedPtr< Peer > toSave; - { - RWMutex::Lock l1(m_peers_l); - const Map< Address, SharedPtr< Peer > >::iterator p(m_peers.find(*i)); - if (p != m_peers.end()) { - p->second.swap(toSave); - m_peers.erase(p); - } - } - if (toSave) - toSave->save(m_ctx, cc); - } - } - } - - { - Vector< Path * > toDelete; - { - RWMutex::Lock l1(m_paths_l); - for (Map< Path::Key, SharedPtr< Path > >::iterator i(m_paths.begin()); i != m_paths.end();) { - Path *const d = i->second.weakGC(); - if (likely(d == nullptr)) { - ++i; - } else { - m_paths.erase(i++); - try { - toDelete.push_back(d); - } catch (...) { - delete d; - } - } - } - } - if (!toDelete.empty()) { - for (Vector< Path * >::iterator i(toDelete.begin()); i != toDelete.end(); ++i) - delete *i; - ZT_SPEW("garbage collected %u orphaned paths", (unsigned int)toDelete.size()); - } - } + allPeers.clear(); + { + RWMutex::RLock l(m_peers_l); + allPeers.reserve(m_peers.size()); + for (Map >::const_iterator i(m_peers.begin()); i != m_peers.end(); ++i) + allPeers.push_back(i->second); + } + { + Mutex::Lock l(m_roots_l); + rootPeers = m_roots; + } } -void Topology::trustStoreChanged(const CallContext &cc) +void Topology::doPeriodicTasks(const CallContext& cc) { - Map< Identity, SharedPtr< const Locator > > roots(m_ctx.ts->roots()); + // Get a list of root peer pointer addresses for filtering during peer cleanup. + Vector rootLookup; + { + Mutex::Lock l(m_roots_l); + m_rankRoots(); + rootLookup.reserve(m_roots.size()); + for (Vector >::const_iterator r(m_roots.begin()); r != m_roots.end(); ++r) + rootLookup.push_back((uintptr_t)r->ptr()); + } + std::sort(rootLookup.begin(), rootLookup.end()); - Vector< SharedPtr< Peer > > newRootList; - newRootList.reserve(roots.size()); + // Cleaning of peers and paths uses a two pass method to avoid write locking + // m_peers or m_paths for any significant amount of time. This avoids pauses + // on nodes with large numbers of peers or paths. + { + Vector
toDelete; + { + RWMutex::RLock l1(m_peers_l); + for (Map >::iterator i(m_peers.begin()); i != m_peers.end(); ++i) { + // TODO: also delete if the peer has not exchanged meaningful communication in a while, such as a + // network frame or non-trivial control packet. + if (((cc.ticks - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) + && (! std::binary_search( + rootLookup.begin(), + rootLookup.end(), + reinterpret_cast(i->second.ptr())))) + toDelete.push_back(i->first); + } + } + if (! toDelete.empty()) { + ZT_SPEW("garbage collecting %u offline or stale peer objects", (unsigned int)toDelete.size()); + for (Vector
::iterator i(toDelete.begin()); i != toDelete.end(); ++i) { + SharedPtr toSave; + { + RWMutex::Lock l1(m_peers_l); + const Map >::iterator p(m_peers.find(*i)); + if (p != m_peers.end()) { + p->second.swap(toSave); + m_peers.erase(p); + } + } + if (toSave) + toSave->save(m_ctx, cc); + } + } + } - for (Map< Identity, SharedPtr< const Locator > >::const_iterator r(roots.begin()); r != roots.end(); ++r) { - SharedPtr< Peer > root(this->peer(cc, r->first.address(), true)); - if (!root) { - root.set(new Peer()); - if (root->init(m_ctx, cc, r->first)) { - root = this->add(cc, root); - } else { - root.zero(); - } - } - if (root) { - newRootList.push_back(root); - if (r->second) - root->setLocator(r->second, true); - } - } - - { - Mutex::Lock l(m_roots_l); - m_roots.swap(newRootList); - m_rankRoots(); - } + { + Vector toDelete; + { + RWMutex::Lock l1(m_paths_l); + for (Map >::iterator i(m_paths.begin()); i != m_paths.end();) { + Path* const d = i->second.weakGC(); + if (likely(d == nullptr)) { + ++i; + } + else { + m_paths.erase(i++); + try { + toDelete.push_back(d); + } + catch (...) { + delete d; + } + } + } + } + if (! toDelete.empty()) { + for (Vector::iterator i(toDelete.begin()); i != toDelete.end(); ++i) + delete *i; + ZT_SPEW("garbage collected %u orphaned paths", (unsigned int)toDelete.size()); + } + } } -void Topology::saveAll(const CallContext &cc) +void Topology::trustStoreChanged(const CallContext& cc) { - RWMutex::RLock l(m_peers_l); - for (Map< Address, SharedPtr< Peer > >::iterator i(m_peers.begin()); i != m_peers.end(); ++i) - i->second->save(m_ctx, cc); + Map > roots(m_ctx.ts->roots()); + + Vector > newRootList; + newRootList.reserve(roots.size()); + + for (Map >::const_iterator r(roots.begin()); r != roots.end(); ++r) { + SharedPtr root(this->peer(cc, r->first.address(), true)); + if (! root) { + root.set(new Peer()); + if (root->init(m_ctx, cc, r->first)) { + root = this->add(cc, root); + } + else { + root.zero(); + } + } + if (root) { + newRootList.push_back(root); + if (r->second) + root->setLocator(r->second, true); + } + } + + { + Mutex::Lock l(m_roots_l); + m_roots.swap(newRootList); + m_rankRoots(); + } } -struct p_RootRankingComparisonOperator +void Topology::saveAll(const CallContext& cc) { - ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept - { - // Sort roots first in order of which root has spoken most recently, but - // only at a resolution of ZT_PATH_KEEPALIVE_PERIOD/2 units of time. This - // means that living roots that seem responsive are ranked the same. Then - // they're sorted in descending order of latency so that the apparently - // fastest root is ranked first. - const int64_t alr = a->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2); - const int64_t blr = b->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2); - if (alr < blr) { - return true; - } else if (blr == alr) { - const int bb = b->latency(); - if (bb < 0) - return true; - return bb < a->latency(); - } - return false; - } + RWMutex::RLock l(m_peers_l); + for (Map >::iterator i(m_peers.begin()); i != m_peers.end(); ++i) + i->second->save(m_ctx, cc); +} + +struct p_RootRankingComparisonOperator { + ZT_INLINE bool operator()(const SharedPtr& a, const SharedPtr& b) const noexcept + { + // Sort roots first in order of which root has spoken most recently, but + // only at a resolution of ZT_PATH_KEEPALIVE_PERIOD/2 units of time. This + // means that living roots that seem responsive are ranked the same. Then + // they're sorted in descending order of latency so that the apparently + // fastest root is ranked first. + const int64_t alr = a->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2); + const int64_t blr = b->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2); + if (alr < blr) { + return true; + } + else if (blr == alr) { + const int bb = b->latency(); + if (bb < 0) + return true; + return bb < a->latency(); + } + return false; + } }; void Topology::m_rankRoots() { - // assumes m_roots is locked - if (unlikely(m_roots.empty())) { - l_bestRoot.lock(); - m_bestRoot.zero(); - l_bestRoot.unlock(); - } else { - std::sort(m_roots.begin(), m_roots.end(), p_RootRankingComparisonOperator()); - l_bestRoot.lock(); - m_bestRoot = m_roots.front(); - l_bestRoot.unlock(); - } + // assumes m_roots is locked + if (unlikely(m_roots.empty())) { + l_bestRoot.lock(); + m_bestRoot.zero(); + l_bestRoot.unlock(); + } + else { + std::sort(m_roots.begin(), m_roots.end(), p_RootRankingComparisonOperator()); + l_bestRoot.lock(); + m_bestRoot = m_roots.front(); + l_bestRoot.unlock(); + } } -void Topology::m_loadCached(const CallContext &cc, const Address &zta, SharedPtr< Peer > &peer) +void Topology::m_loadCached(const CallContext& cc, const Address& zta, SharedPtr& peer) { - // does not require any locks to be held + // does not require any locks to be held - try { - uint64_t id[2]; - id[0] = zta.toInt(); - id[1] = 0; - Vector< uint8_t > data(m_ctx.store->get(cc, ZT_STATE_OBJECT_PEER, id, 1)); - if (data.size() > 8) { - const uint8_t *d = data.data(); - int dl = (int)data.size(); + try { + uint64_t id[2]; + id[0] = zta.toInt(); + id[1] = 0; + Vector data(m_ctx.store->get(cc, ZT_STATE_OBJECT_PEER, id, 1)); + if (data.size() > 8) { + const uint8_t* d = data.data(); + int dl = (int)data.size(); - const int64_t ts = (int64_t)Utils::loadBigEndian< uint64_t >(d); - Peer *const p = new Peer(); - int n = p->unmarshal(m_ctx, cc.ticks, d + 8, dl - 8); - if (n < 0) { - delete p; - return; - } - if ((cc.ticks - ts) < ZT_PEER_GLOBAL_TIMEOUT) { - // TODO: handle many peers, same address (?) - peer.set(p); - return; - } - } - } catch (...) { - peer.zero(); - } + const int64_t ts = (int64_t)Utils::loadBigEndian(d); + Peer* const p = new Peer(); + int n = p->unmarshal(m_ctx, cc.ticks, d + 8, dl - 8); + if (n < 0) { + delete p; + return; + } + if ((cc.ticks - ts) < ZT_PEER_GLOBAL_TIMEOUT) { + // TODO: handle many peers, same address (?) + peer.set(p); + return; + } + } + } + catch (...) { + peer.zero(); + } } -SharedPtr< Peer > Topology::m_peerFromCached(const CallContext &cc, const Address &zta) +SharedPtr Topology::m_peerFromCached(const CallContext& cc, const Address& zta) { - SharedPtr< Peer > p; - m_loadCached(cc, zta, p); - if (p) { - RWMutex::Lock l(m_peers_l); - SharedPtr< Peer > &hp = m_peers[zta]; - if (hp) - return hp; - hp = p; - } - return p; + SharedPtr p; + m_loadCached(cc, zta, p); + if (p) { + RWMutex::Lock l(m_peers_l); + SharedPtr& hp = m_peers[zta]; + if (hp) + return hp; + hp = p; + } + return p; } -SharedPtr< Path > Topology::m_newPath(const int64_t l, const InetAddress &r, const Path::Key &k) +SharedPtr Topology::m_newPath(const int64_t l, const InetAddress& r, const Path::Key& k) { - SharedPtr< Path > p(new Path(l, r)); - RWMutex::Lock lck(m_paths_l); - SharedPtr< Path > &p2 = m_paths[k]; - if (p2) - return p2; - p2 = p; - return p; + SharedPtr p(new Path(l, r)); + RWMutex::Lock lck(m_paths_l); + SharedPtr& p2 = m_paths[k]; + if (p2) + return p2; + p2 = p; + return p; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Topology.hpp b/core/Topology.hpp index 48d362be4..f7a19237f 100644 --- a/core/Topology.hpp +++ b/core/Topology.hpp @@ -14,21 +14,21 @@ #ifndef ZT_TOPOLOGY_HPP #define ZT_TOPOLOGY_HPP -#include "Constants.hpp" #include "Address.hpp" -#include "Identity.hpp" -#include "Peer.hpp" -#include "Path.hpp" -#include "Mutex.hpp" -#include "InetAddress.hpp" -#include "SharedPtr.hpp" -#include "ScopedPtr.hpp" -#include "Fingerprint.hpp" -#include "FCV.hpp" -#include "Certificate.hpp" -#include "Containers.hpp" -#include "Spinlock.hpp" #include "CallContext.hpp" +#include "Certificate.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "FCV.hpp" +#include "Fingerprint.hpp" +#include "Identity.hpp" +#include "InetAddress.hpp" +#include "Mutex.hpp" +#include "Path.hpp" +#include "Peer.hpp" +#include "ScopedPtr.hpp" +#include "SharedPtr.hpp" +#include "Spinlock.hpp" namespace ZeroTier { @@ -37,136 +37,135 @@ class Context; /** * Database of network topology */ -class Topology -{ -public: - Topology(const Context &ctx, const CallContext &cc); +class Topology { + public: + Topology(const Context& ctx, const CallContext& cc); - /** - * Add peer to database - * - * If there's already a peer with this address, the existing peer is - * returned. Otherwise the new peer is added and returned. - * - * @param peer Peer to add - * @return New or existing peer - */ - SharedPtr< Peer > add(const CallContext &cc, const SharedPtr< Peer > &peer); + /** + * Add peer to database + * + * If there's already a peer with this address, the existing peer is + * returned. Otherwise the new peer is added and returned. + * + * @param peer Peer to add + * @return New or existing peer + */ + SharedPtr add(const CallContext& cc, const SharedPtr& peer); - /** - * Get a peer from its address - * - * @param zta ZeroTier address of peer - * @param loadFromCached If false do not load from cache if not in memory (default: true) - * @return Peer or NULL if not found - */ - ZT_INLINE SharedPtr< Peer > peer(const CallContext &cc, const Address &zta, const bool loadFromCached = true) - { - { - RWMutex::RLock l(m_peers_l); - Map< Address, SharedPtr< Peer > >::const_iterator ap(m_peers.find(zta)); - if (likely(ap != m_peers.end())) - return ap->second; - } - if (loadFromCached) - return m_peerFromCached(cc, zta); - return SharedPtr< Peer >(); - } + /** + * Get a peer from its address + * + * @param zta ZeroTier address of peer + * @param loadFromCached If false do not load from cache if not in memory (default: true) + * @return Peer or NULL if not found + */ + ZT_INLINE SharedPtr peer(const CallContext& cc, const Address& zta, const bool loadFromCached = true) + { + { + RWMutex::RLock l(m_peers_l); + Map >::const_iterator ap(m_peers.find(zta)); + if (likely(ap != m_peers.end())) + return ap->second; + } + if (loadFromCached) + return m_peerFromCached(cc, zta); + return SharedPtr(); + } - /** - * Get a Path object for a given local and remote physical address, creating if needed - * - * @param l Local socket - * @param r Remote address - * @return Pointer to canonicalized Path object or NULL on error - */ - ZT_INLINE SharedPtr< Path > path(const int64_t l, const InetAddress &r) - { - const Path::Key k(r); - { - RWMutex::RLock lck(m_paths_l); - Map< Path::Key, SharedPtr< Path > >::const_iterator p(m_paths.find(k)); - if (likely(p != m_paths.end())) - return p->second; - } - return m_newPath(l, r, k); - } + /** + * Get a Path object for a given local and remote physical address, creating if needed + * + * @param l Local socket + * @param r Remote address + * @return Pointer to canonicalized Path object or NULL on error + */ + ZT_INLINE SharedPtr path(const int64_t l, const InetAddress& r) + { + const Path::Key k(r); + { + RWMutex::RLock lck(m_paths_l); + Map >::const_iterator p(m_paths.find(k)); + if (likely(p != m_paths.end())) + return p->second; + } + return m_newPath(l, r, k); + } - /** - * Get current best root - * - * @return Root peer or nullptr if none - */ - ZT_INLINE SharedPtr< Peer > root() - { - l_bestRoot.lock(); // spinlock - SharedPtr< Peer > r(m_bestRoot); - l_bestRoot.unlock(); - return r; - } + /** + * Get current best root + * + * @return Root peer or nullptr if none + */ + ZT_INLINE SharedPtr root() + { + l_bestRoot.lock(); // spinlock + SharedPtr r(m_bestRoot); + l_bestRoot.unlock(); + return r; + } - /** - * Get current best root by setting a result parameter - * - * @param root Set to best root or nullptr if none - */ - ZT_INLINE void root(SharedPtr< Peer > &root) - { - l_bestRoot.lock(); // spinlock - root = m_bestRoot; - l_bestRoot.unlock(); - } + /** + * Get current best root by setting a result parameter + * + * @param root Set to best root or nullptr if none + */ + ZT_INLINE void root(SharedPtr& root) + { + l_bestRoot.lock(); // spinlock + root = m_bestRoot; + l_bestRoot.unlock(); + } - /** - * @param allPeers Vector to fill with all current peers - * @param rootPeers Vector to fill with peers that are roots - */ - void allPeers(Vector< SharedPtr< Peer > > &allPeers, Vector< SharedPtr< Peer > > &rootPeers) const; + /** + * @param allPeers Vector to fill with all current peers + * @param rootPeers Vector to fill with peers that are roots + */ + void allPeers(Vector >& allPeers, Vector >& rootPeers) const; - /** - * Do periodic tasks such as database cleanup, cert cleanup, root ranking, etc. - */ - void doPeriodicTasks(const CallContext &cc); + /** + * Do periodic tasks such as database cleanup, cert cleanup, root ranking, etc. + */ + void doPeriodicTasks(const CallContext& cc); - /** - * Rank root servers in descending order of quality - */ - ZT_INLINE void rankRoots(const CallContext &cc) - { - Mutex::Lock l(m_roots_l); - m_rankRoots(); - } + /** + * Rank root servers in descending order of quality + */ + ZT_INLINE void rankRoots(const CallContext& cc) + { + Mutex::Lock l(m_roots_l); + m_rankRoots(); + } - /** - * Perform internal updates based on changes in the trust store - */ - void trustStoreChanged(const CallContext &cc); + /** + * Perform internal updates based on changes in the trust store + */ + void trustStoreChanged(const CallContext& cc); - /** - * Save all currently known peers to data store - */ - void saveAll(const CallContext &cc); + /** + * Save all currently known peers to data store + */ + void saveAll(const CallContext& cc); -private: - void m_rankRoots(); - void m_loadCached(const CallContext &cc, const Address &zta, SharedPtr< Peer > &peer); - SharedPtr< Peer > m_peerFromCached(const CallContext &cc, const Address &zta); - SharedPtr< Path > m_newPath(int64_t l, const InetAddress &r, const Path::Key &k); + private: + void m_rankRoots(); + void m_loadCached(const CallContext& cc, const Address& zta, SharedPtr& peer); + SharedPtr m_peerFromCached(const CallContext& cc, const Address& zta); + SharedPtr m_newPath(int64_t l, const InetAddress& r, const Path::Key& k); - const Context &m_ctx; + const Context& m_ctx; - Vector< SharedPtr< Peer > > m_roots; - Map< Address, SharedPtr< Peer > > m_peers; - Map< Path::Key, SharedPtr< Path > > m_paths; + Vector > m_roots; + Map > m_peers; + Map > m_paths; - RWMutex m_peers_l; // m_peers - RWMutex m_paths_l; // m_paths - Mutex m_roots_l; // m_roots + RWMutex m_peers_l; // m_peers + RWMutex m_paths_l; // m_paths + Mutex m_roots_l; // m_roots - SharedPtr< Peer > m_bestRoot; - Spinlock l_bestRoot; + SharedPtr m_bestRoot; + Spinlock l_bestRoot; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Trace.cpp b/core/Trace.cpp index 24b7f97e0..a207cbf4f 100644 --- a/core/Trace.cpp +++ b/core/Trace.cpp @@ -12,280 +12,285 @@ /****/ #include "Trace.hpp" + #include "Context.hpp" +#include "FCV.hpp" +#include "InetAddress.hpp" #include "Node.hpp" #include "Peer.hpp" -#include "InetAddress.hpp" -#include "FCV.hpp" // NOTE: packet IDs are always handled in network byte order, so no need to convert them. namespace ZeroTier { -Trace::Trace(const Context &ctx) : - m_ctx(ctx), - m_traceFlags(0) -{} - -void Trace::unexpectedError( - const CallContext &cc, - uint32_t codeLocation, - const char *message, - ...) +Trace::Trace(const Context& ctx) : m_ctx(ctx), m_traceFlags(0) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_UNEXPECTED_ERROR); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_MESSAGE, message); - buf.push_back(0); - m_ctx.node->postEvent(cc.tPtr, ZT_EVENT_TRACE, buf.data()); +} + +void Trace::unexpectedError(const CallContext& cc, uint32_t codeLocation, const char* message, ...) +{ + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_UNEXPECTED_ERROR); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_MESSAGE, message); + buf.push_back(0); + m_ctx.node->postEvent(cc.tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_resettingPathsInScope( - void *tPtr, - uint32_t codeLocation, - const Identity &reporter, - const InetAddress &from, - const InetAddress &oldExternal, - const InetAddress &newExternal, - ZT_InetAddress_IpScope scope) + void* tPtr, + uint32_t codeLocation, + const Identity& reporter, + const InetAddress& from, + const InetAddress& oldExternal, + const InetAddress& newExternal, + ZT_InetAddress_IpScope scope) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - if (reporter) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, reporter.fingerprint()); - if (from) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(from)); - if (oldExternal) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(oldExternal)); - if (newExternal) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_NEW_ENDPOINT, Endpoint(newExternal)); - Dictionary::append(buf, ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE, scope); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + if (reporter) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, reporter.fingerprint()); + if (from) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(from)); + if (oldExternal) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(oldExternal)); + if (newExternal) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_NEW_ENDPOINT, Endpoint(newExternal)); + Dictionary::append(buf, ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE, scope); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_tryingNewPath( - void *tPtr, - uint32_t codeLocation, - const Identity &trying, - const InetAddress &physicalAddress, - const InetAddress &triggerAddress, - uint64_t triggeringPacketId, - uint8_t triggeringPacketVerb, - const Identity &triggeringPeer) + void* tPtr, + uint32_t codeLocation, + const Identity& trying, + const InetAddress& physicalAddress, + const InetAddress& triggerAddress, + uint64_t triggeringPacketId, + uint8_t triggeringPacketVerb, + const Identity& triggeringPeer) { - if ((trying)&&(physicalAddress)) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint()); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, physicalAddress); - if (triggerAddress) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress)); - Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId); - Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb); - if (triggeringPeer) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT, triggeringPeer.fingerprint()); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); - } + if ((trying) && (physicalAddress)) { + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint()); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, physicalAddress); + if (triggerAddress) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress)); + Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId); + Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb); + if (triggeringPeer) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT, triggeringPeer.fingerprint()); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + } } void Trace::m_learnedNewPath( - void *tPtr, - uint32_t codeLocation, - uint64_t packetId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - const InetAddress &replaced) + void* tPtr, + uint32_t codeLocation, + uint64_t packetId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + const InetAddress& replaced) { - if (peerIdentity) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); - if (physicalAddress) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); - if (replaced) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(replaced)); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); - } + if (peerIdentity) { + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); + if (physicalAddress) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); + if (replaced) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(replaced)); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + } } void Trace::m_incomingPacketDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t packetId, - uint64_t networkId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint8_t verb, - ZT_TracePacketDropReason reason) + void* tPtr, + uint32_t codeLocation, + uint64_t packetId, + uint64_t networkId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint8_t verb, + ZT_TracePacketDropReason reason) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - if (peerIdentity) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); - if (physicalAddress) - Dictionary::append(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); - Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); - Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb); - Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + if (peerIdentity) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); + if (physicalAddress) + Dictionary::append(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); + Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); + Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb); + Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_outgoingNetworkFrameDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - uint16_t etherType, - uint16_t frameLength, - const uint8_t *frameData, - ZT_TraceFrameDropReason reason) + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + uint16_t etherType, + uint16_t frameLength, + const uint8_t* frameData, + ZT_TraceFrameDropReason reason) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); - if (frameData) - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); - Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); + Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); + if (frameData) + Dictionary::append( + buf, + ZT_TRACE_FIELD_FRAME_DATA, + frameData, + std::min((unsigned int)64, (unsigned int)frameLength)); + Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_incomingNetworkFrameDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - const uint16_t etherType, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint16_t frameLength, - const uint8_t *frameData, - uint8_t verb, - bool credentialRequestSent, - ZT_TraceFrameDropReason reason) + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + const uint16_t etherType, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint16_t frameLength, + const uint8_t* frameData, + uint8_t verb, + bool credentialRequestSent, + ZT_TraceFrameDropReason reason) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); - if (physicalAddress) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); - Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); - Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb); - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); - if (frameData) - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); - Dictionary::append(buf, ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT, credentialRequestSent); - Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); + if (physicalAddress) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); + Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); + Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb); + Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); + if (frameData) + Dictionary::append( + buf, + ZT_TRACE_FIELD_FRAME_DATA, + frameData, + std::min((unsigned int)64, (unsigned int)frameLength)); + Dictionary::append(buf, ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT, credentialRequestSent); + Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } -void Trace::m_networkConfigRequestSent( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId) +void Trace::m_networkConfigRequestSent(void* tPtr, uint32_t codeLocation, uint64_t networkId) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_networkFilter( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const uint8_t *primaryRuleSetLog, - const uint8_t *matchingCapabilityRuleSetLog, - uint32_t matchingCapabilityId, - int64_t matchingCapabilityTimestamp, - const Address &source, - const Address &dest, - const MAC &sourceMac, - const MAC &destMac, - uint16_t frameLength, - const uint8_t *frameData, - uint16_t etherType, - uint16_t vlanId, - bool noTee, - bool inbound, - int accept) + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const uint8_t* primaryRuleSetLog, + const uint8_t* matchingCapabilityRuleSetLog, + uint32_t matchingCapabilityId, + int64_t matchingCapabilityTimestamp, + const Address& source, + const Address& dest, + const MAC& sourceMac, + const MAC& destMac, + uint16_t frameLength, + const uint8_t* frameData, + uint16_t etherType, + uint16_t vlanId, + bool noTee, + bool inbound, + int accept) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_FILTER); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - if ((primaryRuleSetLog) && (!Utils::allZero(primaryRuleSetLog, 512))) - Dictionary::append(buf, ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG, primaryRuleSetLog, 512); - if ((matchingCapabilityRuleSetLog) && (!Utils::allZero(matchingCapabilityRuleSetLog, 512))) - Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG, matchingCapabilityRuleSetLog, 512); - Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID, matchingCapabilityId); - Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP, matchingCapabilityTimestamp); - Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS, source); - Dictionary::append(buf, ZT_TRACE_FIELD_DEST_ZT_ADDRESS, dest); - Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); - if (frameData) - Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); - Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); - Dictionary::append(buf, ZT_TRACE_FIELD_VLAN_ID, vlanId); - Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_NOTEE, noTee); - Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_INBOUND, inbound); - Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_ACCEPT, (int32_t)accept); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_FILTER); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + if ((primaryRuleSetLog) && (! Utils::allZero(primaryRuleSetLog, 512))) + Dictionary::append(buf, ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG, primaryRuleSetLog, 512); + if ((matchingCapabilityRuleSetLog) && (! Utils::allZero(matchingCapabilityRuleSetLog, 512))) + Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG, matchingCapabilityRuleSetLog, 512); + Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID, matchingCapabilityId); + Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP, matchingCapabilityTimestamp); + Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS, source); + Dictionary::append(buf, ZT_TRACE_FIELD_DEST_ZT_ADDRESS, dest); + Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); + Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); + if (frameData) + Dictionary::append( + buf, + ZT_TRACE_FIELD_FRAME_DATA, + frameData, + std::min((unsigned int)64, (unsigned int)frameLength)); + Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); + Dictionary::append(buf, ZT_TRACE_FIELD_VLAN_ID, vlanId); + Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_NOTEE, noTee); + Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_INBOUND, inbound); + Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_ACCEPT, (int32_t)accept); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } void Trace::m_credentialRejected( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const Identity &identity, - uint32_t credentialId, - int64_t credentialTimestamp, - uint8_t credentialType, - ZT_TraceCredentialRejectionReason reason) + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const Identity& identity, + uint32_t credentialId, + int64_t credentialTimestamp, + uint8_t credentialType, + ZT_TraceCredentialRejectionReason reason) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, identity.fingerprint()); - Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_ID, credentialId); - Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP, credentialTimestamp); - Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TYPE, credentialType); - Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); - buf.push_back(0); - m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + FCV buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, identity.fingerprint()); + Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_ID, credentialId); + Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP, credentialTimestamp); + Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TYPE, credentialType); + Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); + buf.push_back(0); + m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Trace.hpp b/core/Trace.hpp index be537f932..a082a7db4 100644 --- a/core/Trace.hpp +++ b/core/Trace.hpp @@ -14,15 +14,15 @@ #ifndef ZT_TRACE_HPP #define ZT_TRACE_HPP -#include "Constants.hpp" -#include "SharedPtr.hpp" -#include "Mutex.hpp" -#include "InetAddress.hpp" #include "Address.hpp" -#include "MAC.hpp" -#include "Containers.hpp" -#include "Utils.hpp" #include "CallContext.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" +#include "Mutex.hpp" +#include "SharedPtr.hpp" +#include "Utils.hpp" #define ZT_TRACE_F_VL1 0x01U #define ZT_TRACE_F_VL2 0x02U @@ -56,291 +56,333 @@ struct NetworkConfig; * turned into constants that are semi-official and stored in a database to * provide extra debug context. */ -class Trace -{ -public: - struct RuleResultLog : public TriviallyCopyable - { - uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields +class Trace { + public: + struct RuleResultLog : public TriviallyCopyable { + uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields - ZT_INLINE void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) noexcept - { l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U); } + ZT_INLINE void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) noexcept + { + l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U); + } - ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept - { l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); } + ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept + { + l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); + } - ZT_INLINE void clear() noexcept - { memoryZero(this); } - }; + ZT_INLINE void clear() noexcept + { + memoryZero(this); + } + }; - explicit Trace(const Context &ctx); + explicit Trace(const Context& ctx); - void unexpectedError( - const CallContext &cc, - uint32_t codeLocation, - const char *message, - ...); + void unexpectedError(const CallContext& cc, uint32_t codeLocation, const char* message, ...); - ZT_INLINE void resettingPathsInScope( - const CallContext &cc, - const uint32_t codeLocation, - const Identity &reporter, - const InetAddress &from, - const InetAddress &oldExternal, - const InetAddress &newExternal, - const InetAddress::IpScope scope) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) - m_resettingPathsInScope(cc.tPtr, codeLocation, reporter, from, oldExternal, newExternal, scope); - } + ZT_INLINE void resettingPathsInScope( + const CallContext& cc, + const uint32_t codeLocation, + const Identity& reporter, + const InetAddress& from, + const InetAddress& oldExternal, + const InetAddress& newExternal, + const InetAddress::IpScope scope) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) + m_resettingPathsInScope(cc.tPtr, codeLocation, reporter, from, oldExternal, newExternal, scope); + } - ZT_INLINE void tryingNewPath( - const CallContext &cc, - const uint32_t codeLocation, - const Identity &trying, - const InetAddress &physicalAddress, - const InetAddress &triggerAddress, - uint64_t triggeringPacketId, - uint8_t triggeringPacketVerb, - const Identity &triggeringPeer) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) - m_tryingNewPath(cc.tPtr, codeLocation, trying, physicalAddress, triggerAddress, triggeringPacketId, triggeringPacketVerb, triggeringPeer); - } + ZT_INLINE void tryingNewPath( + const CallContext& cc, + const uint32_t codeLocation, + const Identity& trying, + const InetAddress& physicalAddress, + const InetAddress& triggerAddress, + uint64_t triggeringPacketId, + uint8_t triggeringPacketVerb, + const Identity& triggeringPeer) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) + m_tryingNewPath( + cc.tPtr, + codeLocation, + trying, + physicalAddress, + triggerAddress, + triggeringPacketId, + triggeringPacketVerb, + triggeringPeer); + } - ZT_INLINE void learnedNewPath( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t packetId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - const InetAddress &replaced) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) - m_learnedNewPath(cc.tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced); - } + ZT_INLINE void learnedNewPath( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t packetId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + const InetAddress& replaced) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) + m_learnedNewPath(cc.tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced); + } - ZT_INLINE void incomingPacketDropped( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t packetId, - uint64_t networkId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint8_t verb, - const ZT_TracePacketDropReason reason) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) - m_incomingPacketDropped(cc.tPtr, codeLocation, packetId, networkId, peerIdentity, physicalAddress, hops, verb, reason); - } + ZT_INLINE void incomingPacketDropped( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t packetId, + uint64_t networkId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint8_t verb, + const ZT_TracePacketDropReason reason) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) + m_incomingPacketDropped( + cc.tPtr, + codeLocation, + packetId, + networkId, + peerIdentity, + physicalAddress, + hops, + verb, + reason); + } - ZT_INLINE void outgoingNetworkFrameDropped( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - uint16_t etherType, - uint16_t frameLength, - const uint8_t *frameData, - ZT_TraceFrameDropReason reason) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) - m_outgoingNetworkFrameDropped(cc.tPtr, codeLocation, networkId, sourceMac, destMac, etherType, frameLength, frameData, reason); - } + ZT_INLINE void outgoingNetworkFrameDropped( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + uint16_t etherType, + uint16_t frameLength, + const uint8_t* frameData, + ZT_TraceFrameDropReason reason) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) + m_outgoingNetworkFrameDropped( + cc.tPtr, + codeLocation, + networkId, + sourceMac, + destMac, + etherType, + frameLength, + frameData, + reason); + } - ZT_INLINE void incomingNetworkFrameDropped( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - const uint16_t etherType, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint16_t frameLength, - const uint8_t *frameData, - uint8_t verb, - bool credentialRequestSent, - ZT_TraceFrameDropReason reason) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) - m_incomingNetworkFrameDropped(cc.tPtr, codeLocation, networkId, sourceMac, destMac, etherType, peerIdentity, physicalAddress, hops, frameLength, frameData, verb, credentialRequestSent, reason); - } + ZT_INLINE void incomingNetworkFrameDropped( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + const uint16_t etherType, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint16_t frameLength, + const uint8_t* frameData, + uint8_t verb, + bool credentialRequestSent, + ZT_TraceFrameDropReason reason) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) + m_incomingNetworkFrameDropped( + cc.tPtr, + codeLocation, + networkId, + sourceMac, + destMac, + etherType, + peerIdentity, + physicalAddress, + hops, + frameLength, + frameData, + verb, + credentialRequestSent, + reason); + } - ZT_INLINE void networkConfigRequestSent( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t networkId) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) - m_networkConfigRequestSent(cc.tPtr, codeLocation, networkId); - } + ZT_INLINE void networkConfigRequestSent(const CallContext& cc, const uint32_t codeLocation, uint64_t networkId) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) + m_networkConfigRequestSent(cc.tPtr, codeLocation, networkId); + } - ZT_INLINE void networkFilter( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t networkId, - const uint8_t primaryRuleSetLog[512], - const uint8_t matchingCapabilityRuleSetLog[512], - uint32_t matchingCapabilityId, - int64_t matchingCapabilityTimestamp, - const Address &source, - const Address &dest, - const MAC &sourceMac, - const MAC &destMac, - uint16_t frameLength, - const uint8_t *frameData, - uint16_t etherType, - uint16_t vlanId, - bool noTee, - bool inbound, - int accept) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL2_FILTER) != 0)) { - m_networkFilter( - cc.tPtr, - codeLocation, - networkId, - primaryRuleSetLog, - matchingCapabilityRuleSetLog, - matchingCapabilityId, - matchingCapabilityTimestamp, - source, - dest, - sourceMac, - destMac, - frameLength, - frameData, - etherType, - vlanId, - noTee, - inbound, - accept); - } - } + ZT_INLINE void networkFilter( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t networkId, + const uint8_t primaryRuleSetLog[512], + const uint8_t matchingCapabilityRuleSetLog[512], + uint32_t matchingCapabilityId, + int64_t matchingCapabilityTimestamp, + const Address& source, + const Address& dest, + const MAC& sourceMac, + const MAC& destMac, + uint16_t frameLength, + const uint8_t* frameData, + uint16_t etherType, + uint16_t vlanId, + bool noTee, + bool inbound, + int accept) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL2_FILTER) != 0)) { + m_networkFilter( + cc.tPtr, + codeLocation, + networkId, + primaryRuleSetLog, + matchingCapabilityRuleSetLog, + matchingCapabilityId, + matchingCapabilityTimestamp, + source, + dest, + sourceMac, + destMac, + frameLength, + frameData, + etherType, + vlanId, + noTee, + inbound, + accept); + } + } - ZT_INLINE void credentialRejected( - const CallContext &cc, - const uint32_t codeLocation, - uint64_t networkId, - const Identity &identity, - uint32_t credentialId, - int64_t credentialTimestamp, - uint8_t credentialType, - ZT_TraceCredentialRejectionReason reason) - { - if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) - m_credentialRejected(cc.tPtr, codeLocation, networkId, identity, credentialId, credentialTimestamp, credentialType, reason); - } + ZT_INLINE void credentialRejected( + const CallContext& cc, + const uint32_t codeLocation, + uint64_t networkId, + const Identity& identity, + uint32_t credentialId, + int64_t credentialTimestamp, + uint8_t credentialType, + ZT_TraceCredentialRejectionReason reason) + { + if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) + m_credentialRejected( + cc.tPtr, + codeLocation, + networkId, + identity, + credentialId, + credentialTimestamp, + credentialType, + reason); + } -private: - void m_resettingPathsInScope( - void *tPtr, - uint32_t codeLocation, - const Identity &reporter, - const InetAddress &from, - const InetAddress &oldExternal, - const InetAddress &newExternal, - InetAddress::IpScope scope); + private: + void m_resettingPathsInScope( + void* tPtr, + uint32_t codeLocation, + const Identity& reporter, + const InetAddress& from, + const InetAddress& oldExternal, + const InetAddress& newExternal, + InetAddress::IpScope scope); - void m_tryingNewPath( - void *tPtr, - uint32_t codeLocation, - const Identity &trying, - const InetAddress &physicalAddress, - const InetAddress &triggerAddress, - uint64_t triggeringPacketId, - uint8_t triggeringPacketVerb, - const Identity &triggeringPeer); + void m_tryingNewPath( + void* tPtr, + uint32_t codeLocation, + const Identity& trying, + const InetAddress& physicalAddress, + const InetAddress& triggerAddress, + uint64_t triggeringPacketId, + uint8_t triggeringPacketVerb, + const Identity& triggeringPeer); - void m_learnedNewPath( - void *tPtr, - uint32_t codeLocation, - uint64_t packetId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - const InetAddress &replaced); + void m_learnedNewPath( + void* tPtr, + uint32_t codeLocation, + uint64_t packetId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + const InetAddress& replaced); - void m_incomingPacketDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t packetId, - uint64_t networkId, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint8_t verb, - ZT_TracePacketDropReason reason); + void m_incomingPacketDropped( + void* tPtr, + uint32_t codeLocation, + uint64_t packetId, + uint64_t networkId, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint8_t verb, + ZT_TracePacketDropReason reason); - void m_outgoingNetworkFrameDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - uint16_t etherType, - uint16_t frameLength, - const uint8_t *frameData, - ZT_TraceFrameDropReason reason); + void m_outgoingNetworkFrameDropped( + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + uint16_t etherType, + uint16_t frameLength, + const uint8_t* frameData, + ZT_TraceFrameDropReason reason); - void m_incomingNetworkFrameDropped( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const MAC &sourceMac, - const MAC &destMac, - const uint16_t etherType, - const Identity &peerIdentity, - const InetAddress &physicalAddress, - uint8_t hops, - uint16_t frameLength, - const uint8_t *frameData, - uint8_t verb, - bool credentialRequestSent, - ZT_TraceFrameDropReason reason); + void m_incomingNetworkFrameDropped( + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const MAC& sourceMac, + const MAC& destMac, + const uint16_t etherType, + const Identity& peerIdentity, + const InetAddress& physicalAddress, + uint8_t hops, + uint16_t frameLength, + const uint8_t* frameData, + uint8_t verb, + bool credentialRequestSent, + ZT_TraceFrameDropReason reason); - void m_networkConfigRequestSent( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId); + void m_networkConfigRequestSent(void* tPtr, uint32_t codeLocation, uint64_t networkId); - void m_networkFilter( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const uint8_t *primaryRuleSetLog, - const uint8_t *matchingCapabilityRuleSetLog, - uint32_t matchingCapabilityId, - int64_t matchingCapabilityTimestamp, - const Address &source, - const Address &dest, - const MAC &sourceMac, - const MAC &destMac, - uint16_t frameLength, - const uint8_t *frameData, - uint16_t etherType, - uint16_t vlanId, - bool noTee, - bool inbound, - int accept); + void m_networkFilter( + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const uint8_t* primaryRuleSetLog, + const uint8_t* matchingCapabilityRuleSetLog, + uint32_t matchingCapabilityId, + int64_t matchingCapabilityTimestamp, + const Address& source, + const Address& dest, + const MAC& sourceMac, + const MAC& destMac, + uint16_t frameLength, + const uint8_t* frameData, + uint16_t etherType, + uint16_t vlanId, + bool noTee, + bool inbound, + int accept); - void m_credentialRejected( - void *tPtr, - uint32_t codeLocation, - uint64_t networkId, - const Identity &identity, - uint32_t credentialId, - int64_t credentialTimestamp, - uint8_t credentialType, - ZT_TraceCredentialRejectionReason reason); + void m_credentialRejected( + void* tPtr, + uint32_t codeLocation, + uint64_t networkId, + const Identity& identity, + uint32_t credentialId, + int64_t credentialTimestamp, + uint8_t credentialType, + ZT_TraceCredentialRejectionReason reason); - const Context &m_ctx; - volatile unsigned int m_traceFlags; // faster than atomic, but may not "instantly" change... should be okay + const Context& m_ctx; + volatile unsigned int m_traceFlags; // faster than atomic, but may not "instantly" change... should be okay }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/TriviallyCopyable.hpp b/core/TriviallyCopyable.hpp index f31e7f417..ca6370aa2 100644 --- a/core/TriviallyCopyable.hpp +++ b/core/TriviallyCopyable.hpp @@ -24,40 +24,41 @@ namespace ZeroTier { * * It also includes some static methods to do this conveniently. */ -struct TriviallyCopyable -{ -public: - /** - * Zero a TriviallyCopyable object - * - * @tparam T Automatically inferred type of object - * @param obj Any TriviallyCopyable object - */ - template - static ZT_INLINE void memoryZero(T *obj) noexcept - { - mustBeTriviallyCopyable(obj); - Utils::zero(obj); - } +struct TriviallyCopyable { + public: + /** + * Zero a TriviallyCopyable object + * + * @tparam T Automatically inferred type of object + * @param obj Any TriviallyCopyable object + */ + template static ZT_INLINE void memoryZero(T* obj) noexcept + { + mustBeTriviallyCopyable(obj); + Utils::zero(obj); + } - /** - * Zero a TriviallyCopyable object - * - * @tparam T Automatically inferred type of object - * @param obj Any TriviallyCopyable object - */ - template - static ZT_INLINE void memoryZero(T &obj) noexcept - { - mustBeTriviallyCopyable(obj); - Utils::zero(&obj); - } + /** + * Zero a TriviallyCopyable object + * + * @tparam T Automatically inferred type of object + * @param obj Any TriviallyCopyable object + */ + template static ZT_INLINE void memoryZero(T& obj) noexcept + { + mustBeTriviallyCopyable(obj); + Utils::zero(&obj); + } -private: - static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable &) noexcept {} - static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable *) noexcept {} + private: + static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable&) noexcept + { + } + static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable*) noexcept + { + } }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/TrustStore.cpp b/core/TrustStore.cpp index 69a318b23..7237be301 100644 --- a/core/TrustStore.cpp +++ b/core/TrustStore.cpp @@ -12,348 +12,376 @@ /****/ #include "TrustStore.hpp" + #include "LZ4.hpp" namespace ZeroTier { TrustStore::TrustStore() -{} +{ +} TrustStore::~TrustStore() -{} - -SharedPtr< TrustStore::Entry > TrustStore::get(const H384 &serial) const { - RWMutex::RLock l(m_lock); - Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.find(serial)); - return (c != m_bySerial.end()) ? c->second : SharedPtr< TrustStore::Entry >(); } -Map< Identity, SharedPtr< const Locator > > TrustStore::roots() +SharedPtr TrustStore::get(const H384& serial) const { - RWMutex::RLock l(m_lock); - Map< Identity, SharedPtr< const Locator > > r; - - // Iterate using m_bySubjectIdentity to only scan certificates with subject identities. - // This map also does not contian error or deprecated certificates. - for (Map< Fingerprint, Vector< SharedPtr< Entry > > >::const_iterator cv(m_bySubjectIdentity.begin()); cv != m_bySubjectIdentity.end(); ++cv) { - for (Vector< SharedPtr< Entry > >::const_iterator c(cv->second.begin()); c != cv->second.end(); ++c) { - - // A root set cert must be marked for this use and authorized to influence this node's config. - if ((((*c)->m_certificate.usageFlags & ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET) != 0) && (((*c)->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG) != 0)) { - - // Add all identities to the root set, and for each entry in the set make sure we have the latest locator if there's more than one cert with one. - for (unsigned int j = 0; j < (*c)->certificate().subject.identityCount; ++j) { - const Identity *const id = reinterpret_cast((*c)->certificate().subject.identities[j].identity); - if ((id) && (*id)) { // sanity check - SharedPtr< const Locator > &existingLoc = r[*id]; - const Locator *const loc = reinterpret_cast((*c)->certificate().subject.identities[j].locator); - if (loc) { - if ((!existingLoc) || (existingLoc->revision() < loc->revision())) - existingLoc.set(new Locator(*loc)); - } - } - } - - } - - } - } - return r; + RWMutex::RLock l(m_lock); + Map >::const_iterator c(m_bySerial.find(serial)); + return (c != m_bySerial.end()) ? c->second : SharedPtr(); } -Vector< SharedPtr< TrustStore::Entry > > TrustStore::all(const bool includeRejectedCertificates) const +Map > TrustStore::roots() { - RWMutex::RLock l(m_lock); - Vector< SharedPtr< Entry > > r; - r.reserve(m_bySerial.size()); - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE)) - r.push_back(c->second); - } - return r; + RWMutex::RLock l(m_lock); + Map > r; + + // Iterate using m_bySubjectIdentity to only scan certificates with subject identities. + // This map also does not contian error or deprecated certificates. + for (Map > >::const_iterator cv(m_bySubjectIdentity.begin()); + cv != m_bySubjectIdentity.end(); + ++cv) { + for (Vector >::const_iterator c(cv->second.begin()); c != cv->second.end(); ++c) { + // A root set cert must be marked for this use and authorized to influence this node's config. + if ((((*c)->m_certificate.usageFlags & ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET) != 0) + && (((*c)->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG) != 0)) { + // Add all identities to the root set, and for each entry in the set make sure we have the latest + // locator if there's more than one cert with one. + for (unsigned int j = 0; j < (*c)->certificate().subject.identityCount; ++j) { + const Identity* const id = + reinterpret_cast((*c)->certificate().subject.identities[j].identity); + if ((id) && (*id)) { // sanity check + SharedPtr& existingLoc = r[*id]; + const Locator* const loc = + reinterpret_cast((*c)->certificate().subject.identities[j].locator); + if (loc) { + if ((! existingLoc) || (existingLoc->revision() < loc->revision())) + existingLoc.set(new Locator(*loc)); + } + } + } + } + } + } + return r; } -void TrustStore::add(const Certificate &cert, const unsigned int localTrust) +Vector > TrustStore::all(const bool includeRejectedCertificates) const { - RWMutex::Lock l(m_lock); - m_addQueue.push_front(SharedPtr< Entry >(new Entry(this->m_lock, cert, localTrust))); + RWMutex::RLock l(m_lock); + Vector > r; + r.reserve(m_bySerial.size()); + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE)) + r.push_back(c->second); + } + return r; } -void TrustStore::erase(const H384 &serial) +void TrustStore::add(const Certificate& cert, const unsigned int localTrust) { - RWMutex::Lock l(m_lock); - m_deleteQueue.push_front(serial); + RWMutex::Lock l(m_lock); + m_addQueue.push_front(SharedPtr(new Entry(this->m_lock, cert, localTrust))); } -bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const purge) +void TrustStore::erase(const H384& serial) { - RWMutex::Lock l(m_lock); - - // Check for certificate time validity status changes. If any of these occur then - // full re-validation is required. - bool errorStateModified = false; - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - const bool timeValid = c->second->m_certificate.verifyTimeWindow(clock); - switch (c->second->m_error) { - case ZT_CERTIFICATE_ERROR_NONE: - case ZT_CERTIFICATE_ERROR_INVALID_CHAIN: - if (!timeValid) { - c->second->m_error = ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; - errorStateModified = true; - } - break; - case ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW: - if (timeValid) { - c->second->m_error = c->second->m_certificate.verify(-1, false); - errorStateModified = true; - } - break; - default: - break; - } - } - - // If there were not any such changes and if the add and delete queues are empty, - // there is nothing more to be done. - if ((!errorStateModified) && (m_addQueue.empty()) && (m_deleteQueue.empty())) - return false; - - // Add new certificates to m_bySerial, which is the master certificate set. They still - // have yet to have their full certificate chains validated. Full signature checking is - // performed here. - while (!m_addQueue.empty()) { - SharedPtr< Entry > &qi = m_addQueue.front(); - qi->m_error = qi->m_certificate.verify(clock, true); - m_bySerial[H384(qi->m_certificate.serialNo)].move(qi); - m_addQueue.pop_front(); - } - - // Delete any certificates enqueued to be deleted. - while (!m_deleteQueue.empty()) { - m_bySerial.erase(m_deleteQueue.front()); - m_deleteQueue.pop_front(); - } - - // Reset flags for deprecation and a cert being on a trust path, which are - // recomputed when chain and subjects are checked below. - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { - c->second->m_subjectDeprecated = false; - c->second->m_onTrustPath = false; - } - } - - // Validate certificate trust paths. - { - Vector< Entry * > visited; - visited.reserve(8); - for (Map< H384, SharedPtr< Entry > >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (!c->second->m_onTrustPath) && ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) { - // Trace the path of each certificate all the way back to a trusted CA. - unsigned int pathLength = 0; - Map< H384, SharedPtr< Entry > >::const_iterator current(c); - visited.clear(); - for (;;) { - if (pathLength <= current->second->m_certificate.maxPathLength) { - - // Check if this cert isn't a CA or already part of a valid trust path. If so then step upward toward CA. - if (((current->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0) && (!current->second->m_onTrustPath)) { - // If the issuer (parent) certificiate is (1) valid, (2) not already visited (to prevent loops), - // and (3) has a public key that matches this cert's issuer public key (sanity check), proceed - // up the certificate graph toward a potential CA. - visited.push_back(current->second.ptr()); - const Map< H384, SharedPtr< Entry > >::const_iterator prevChild(current); - current = m_bySerial.find(H384(current->second->m_certificate.issuer)); - if ((current != m_bySerial.end()) && - (std::find(visited.begin(), visited.end(), current->second.ptr()) == visited.end()) && - (current->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && - (current->second->m_certificate.publicKeySize == prevChild->second->m_certificate.issuerPublicKeySize) && - (memcmp(current->second->m_certificate.publicKey, prevChild->second->m_certificate.issuerPublicKey, current->second->m_certificate.publicKeySize) == 0)) { - ++pathLength; - continue; - } - } else { - // If we've traced this to a root CA, flag its parents as also being on a trust path. Then - // break the loop without setting an error. We don't flag the current cert as being on a - // trust path since no other certificates depend on it. - for (Vector< Entry * >::const_iterator v(visited.begin()); v != visited.end(); ++v) { - if (*v != c->second.ptr()) - (*v)->m_onTrustPath = true; - } - break; - } - - } - - // If we made it here without breaking or continuing, no path to a - // CA was found and the certificate's chain is invalid. - c->second->m_error = ZT_CERTIFICATE_ERROR_INVALID_CHAIN; - break; - } - } - } - } - - // Repopulate mapping of subject unique IDs to their certificates, marking older - // certificates for the same subject as deprecated. A deprecated certificate is not invalid - // but will be purged if it is also not part of a trust path. Error certificates are ignored. - m_bySubjectUniqueId.clear(); - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { - if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { - - const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize; - if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) { - SharedPtr< Entry > &entry = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)]; - if (entry) { - - // If there's already an entry, see if there's a newer certificate for this subject. - if (c->second->m_certificate.subject.timestamp > entry->m_certificate.subject.timestamp) { - entry->m_subjectDeprecated = true; - entry = c->second; - } else if (c->second->m_certificate.subject.timestamp < entry->m_certificate.subject.timestamp) { - c->second->m_subjectDeprecated = true; - } else { - // Equal timestamps should never happen, but handle it anyway by comparing serials. - if (memcmp(c->second->m_certificate.serialNo, entry->m_certificate.serialNo, ZT_CERTIFICATE_HASH_SIZE) > 0) { - entry->m_subjectDeprecated = true; - entry = c->second; - } else { - c->second->m_subjectDeprecated = true; - } - } - - } else { - entry = c->second; - } - } - - } - } - - // Populate mapping of identities to certificates whose subjects reference them, ignoring - // error or deprecated certificates. - m_bySubjectIdentity.clear(); - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (!c->second->m_subjectDeprecated)) { - - for (unsigned int i = 0; i < c->second->m_certificate.subject.identityCount; ++i) { - const Identity *const id = reinterpret_cast(c->second->m_certificate.subject.identities[i].identity); - if ((id) && (*id)) // sanity check - m_bySubjectIdentity[id->fingerprint()].push_back(c->second); - } - - } - } - - // If purge is set, erase and return error and deprecated certs (that are not on a trust path). - if (purge) { - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { - if ( (c->second->error() != ZT_CERTIFICATE_ERROR_NONE) || ((c->second->m_subjectDeprecated) && (!c->second->m_onTrustPath)) ) { - purge->push_back(c->second); - m_bySerial.erase(c++); - } else { - ++c; - } - } - } - - return true; + RWMutex::Lock l(m_lock); + m_deleteQueue.push_front(serial); } -Vector< uint8_t > TrustStore::save() const +bool TrustStore::update(const int64_t clock, Vector >* const purge) { - Vector< uint8_t > comp; + RWMutex::Lock l(m_lock); - int compSize; - { - RWMutex::RLock l(m_lock); + // Check for certificate time validity status changes. If any of these occur then + // full re-validation is required. + bool errorStateModified = false; + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + const bool timeValid = c->second->m_certificate.verifyTimeWindow(clock); + switch (c->second->m_error) { + case ZT_CERTIFICATE_ERROR_NONE: + case ZT_CERTIFICATE_ERROR_INVALID_CHAIN: + if (! timeValid) { + c->second->m_error = ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; + errorStateModified = true; + } + break; + case ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW: + if (timeValid) { + c->second->m_error = c->second->m_certificate.verify(-1, false); + errorStateModified = true; + } + break; + default: + break; + } + } - Vector< uint8_t > b; - b.reserve(4096); + // If there were not any such changes and if the add and delete queues are empty, + // there is nothing more to be done. + if ((! errorStateModified) && (m_addQueue.empty()) && (m_deleteQueue.empty())) + return false; - // A version byte. - b.push_back(0); + // Add new certificates to m_bySerial, which is the master certificate set. They still + // have yet to have their full certificate chains validated. Full signature checking is + // performed here. + while (! m_addQueue.empty()) { + SharedPtr& qi = m_addQueue.front(); + qi->m_error = qi->m_certificate.verify(clock, true); + m_bySerial[H384(qi->m_certificate.serialNo)].move(qi); + m_addQueue.pop_front(); + } - // tuples terminated by a 0 size. - for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { - const Vector< uint8_t > cdata(c->second->certificate().encode()); - const unsigned long size = (uint32_t)cdata.size(); - if ((size > 0) && (size <= 0xffff)) { - b.push_back((uint8_t)(size >> 8U)); - b.push_back((uint8_t)size); - b.insert(b.end(), cdata.begin(), cdata.end()); - const uint32_t localTrust = (uint32_t)c->second->localTrust(); - b.push_back((uint8_t)(localTrust >> 8U)); - b.push_back((uint8_t)localTrust); - } - } - b.push_back(0); - b.push_back(0); + // Delete any certificates enqueued to be deleted. + while (! m_deleteQueue.empty()) { + m_bySerial.erase(m_deleteQueue.front()); + m_deleteQueue.pop_front(); + } - comp.resize((unsigned long)LZ4_COMPRESSBOUND(b.size()) + 8); - compSize = LZ4_compress_fast(reinterpret_cast(b.data()), reinterpret_cast(comp.data() + 8), (int)b.size(), (int)(comp.size() - 8)); - if (unlikely(compSize <= 0)) // shouldn't be possible - return Vector< uint8_t >(); + // Reset flags for deprecation and a cert being on a trust path, which are + // recomputed when chain and subjects are checked below. + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { + c->second->m_subjectDeprecated = false; + c->second->m_onTrustPath = false; + } + } - const uint32_t uncompSize = (uint32_t)b.size(); - Utils::storeBigEndian(comp.data(), uncompSize); - Utils::storeBigEndian(comp.data() + 4, Utils::fnv1a32(b.data(), (unsigned int)uncompSize)); - compSize += 8; - } + // Validate certificate trust paths. + { + Vector visited; + visited.reserve(8); + for (Map >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (! c->second->m_onTrustPath) + && ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) { + // Trace the path of each certificate all the way back to a trusted CA. + unsigned int pathLength = 0; + Map >::const_iterator current(c); + visited.clear(); + for (;;) { + if (pathLength <= current->second->m_certificate.maxPathLength) { + // Check if this cert isn't a CA or already part of a valid trust path. If so then step upward + // toward CA. + if (((current->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0) + && (! current->second->m_onTrustPath)) { + // If the issuer (parent) certificiate is (1) valid, (2) not already visited (to prevent + // loops), and (3) has a public key that matches this cert's issuer public key (sanity + // check), proceed up the certificate graph toward a potential CA. + visited.push_back(current->second.ptr()); + const Map >::const_iterator prevChild(current); + current = m_bySerial.find(H384(current->second->m_certificate.issuer)); + if ((current != m_bySerial.end()) + && (std::find(visited.begin(), visited.end(), current->second.ptr()) == visited.end()) + && (current->second->m_error == ZT_CERTIFICATE_ERROR_NONE) + && (current->second->m_certificate.publicKeySize + == prevChild->second->m_certificate.issuerPublicKeySize) + && (memcmp( + current->second->m_certificate.publicKey, + prevChild->second->m_certificate.issuerPublicKey, + current->second->m_certificate.publicKeySize) + == 0)) { + ++pathLength; + continue; + } + } + else { + // If we've traced this to a root CA, flag its parents as also being on a trust path. Then + // break the loop without setting an error. We don't flag the current cert as being on a + // trust path since no other certificates depend on it. + for (Vector::const_iterator v(visited.begin()); v != visited.end(); ++v) { + if (*v != c->second.ptr()) + (*v)->m_onTrustPath = true; + } + break; + } + } - comp.resize((unsigned long)compSize); - comp.shrink_to_fit(); + // If we made it here without breaking or continuing, no path to a + // CA was found and the certificate's chain is invalid. + c->second->m_error = ZT_CERTIFICATE_ERROR_INVALID_CHAIN; + break; + } + } + } + } - return comp; + // Repopulate mapping of subject unique IDs to their certificates, marking older + // certificates for the same subject as deprecated. A deprecated certificate is not invalid + // but will be purged if it is also not part of a trust path. Error certificates are ignored. + m_bySubjectUniqueId.clear(); + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { + if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { + const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize; + if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) { + SharedPtr& entry = m_bySubjectUniqueId[Blob( + c->second->m_certificate.subject.uniqueId, + uniqueIdSize)]; + if (entry) { + // If there's already an entry, see if there's a newer certificate for this subject. + if (c->second->m_certificate.subject.timestamp > entry->m_certificate.subject.timestamp) { + entry->m_subjectDeprecated = true; + entry = c->second; + } + else if (c->second->m_certificate.subject.timestamp < entry->m_certificate.subject.timestamp) { + c->second->m_subjectDeprecated = true; + } + else { + // Equal timestamps should never happen, but handle it anyway by comparing serials. + if (memcmp( + c->second->m_certificate.serialNo, + entry->m_certificate.serialNo, + ZT_CERTIFICATE_HASH_SIZE) + > 0) { + entry->m_subjectDeprecated = true; + entry = c->second; + } + else { + c->second->m_subjectDeprecated = true; + } + } + } + else { + entry = c->second; + } + } + } + } + + // Populate mapping of identities to certificates whose subjects reference them, ignoring + // error or deprecated certificates. + m_bySubjectIdentity.clear(); + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (! c->second->m_subjectDeprecated)) { + for (unsigned int i = 0; i < c->second->m_certificate.subject.identityCount; ++i) { + const Identity* const id = + reinterpret_cast(c->second->m_certificate.subject.identities[i].identity); + if ((id) && (*id)) // sanity check + m_bySubjectIdentity[id->fingerprint()].push_back(c->second); + } + } + } + + // If purge is set, erase and return error and deprecated certs (that are not on a trust path). + if (purge) { + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { + if ((c->second->error() != ZT_CERTIFICATE_ERROR_NONE) + || ((c->second->m_subjectDeprecated) && (! c->second->m_onTrustPath))) { + purge->push_back(c->second); + m_bySerial.erase(c++); + } + else { + ++c; + } + } + } + + return true; } -int TrustStore::load(const Vector< uint8_t > &data) +Vector TrustStore::save() const { - if (data.size() < 8) - return -1; + Vector comp; - const unsigned int uncompSize = Utils::loadBigEndian< uint32_t >(data.data()); - if ((uncompSize == 0) || (uncompSize > (unsigned int)(data.size() * 128))) - return -1; + int compSize; + { + RWMutex::RLock l(m_lock); - Vector< uint8_t > uncomp; - uncomp.resize(uncompSize); + Vector b; + b.reserve(4096); - if (LZ4_decompress_safe(reinterpret_cast(data.data() + 8), reinterpret_cast(uncomp.data()), (int)(data.size() - 8), (int)uncompSize) != (int)uncompSize) - return -1; - const uint8_t *b = uncomp.data(); - if (Utils::fnv1a32(b, (unsigned int)uncompSize) != Utils::loadBigEndian< uint32_t >(data.data() + 4)) - return -1; - const uint8_t *const eof = b + uncompSize; + // A version byte. + b.push_back(0); - if (*(b++) != 0) // unrecognized version - return -1; + // tuples terminated by a 0 size. + for (Map >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { + const Vector cdata(c->second->certificate().encode()); + const unsigned long size = (uint32_t)cdata.size(); + if ((size > 0) && (size <= 0xffff)) { + b.push_back((uint8_t)(size >> 8U)); + b.push_back((uint8_t)size); + b.insert(b.end(), cdata.begin(), cdata.end()); + const uint32_t localTrust = (uint32_t)c->second->localTrust(); + b.push_back((uint8_t)(localTrust >> 8U)); + b.push_back((uint8_t)localTrust); + } + } + b.push_back(0); + b.push_back(0); - int readCount = 0; + comp.resize((unsigned long)LZ4_COMPRESSBOUND(b.size()) + 8); + compSize = LZ4_compress_fast( + reinterpret_cast(b.data()), + reinterpret_cast(comp.data() + 8), + (int)b.size(), + (int)(comp.size() - 8)); + if (unlikely(compSize <= 0)) // shouldn't be possible + return Vector(); - for (;;) { - if ((b + 2) > eof) - break; - const uint32_t certDataSize = Utils::loadBigEndian< uint16_t >(b); - b += 2; + const uint32_t uncompSize = (uint32_t)b.size(); + Utils::storeBigEndian(comp.data(), uncompSize); + Utils::storeBigEndian(comp.data() + 4, Utils::fnv1a32(b.data(), (unsigned int)uncompSize)); + compSize += 8; + } - if (certDataSize == 0) - break; + comp.resize((unsigned long)compSize); + comp.shrink_to_fit(); - if ((b + certDataSize + 2) > eof) // certificate length + 2 bytes for trust flags - break; - Certificate c; - if (c.decode(b, (unsigned int)certDataSize)) { - b += certDataSize; - this->add(c, Utils::loadBigEndian< uint16_t >(b)); - b += 2; - - ++readCount; - } - } - - return readCount; + return comp; } -} // namespace ZeroTier +int TrustStore::load(const Vector& data) +{ + if (data.size() < 8) + return -1; + + const unsigned int uncompSize = Utils::loadBigEndian(data.data()); + if ((uncompSize == 0) || (uncompSize > (unsigned int)(data.size() * 128))) + return -1; + + Vector uncomp; + uncomp.resize(uncompSize); + + if (LZ4_decompress_safe( + reinterpret_cast(data.data() + 8), + reinterpret_cast(uncomp.data()), + (int)(data.size() - 8), + (int)uncompSize) + != (int)uncompSize) + return -1; + const uint8_t* b = uncomp.data(); + if (Utils::fnv1a32(b, (unsigned int)uncompSize) != Utils::loadBigEndian(data.data() + 4)) + return -1; + const uint8_t* const eof = b + uncompSize; + + if (*(b++) != 0) // unrecognized version + return -1; + + int readCount = 0; + + for (;;) { + if ((b + 2) > eof) + break; + const uint32_t certDataSize = Utils::loadBigEndian(b); + b += 2; + + if (certDataSize == 0) + break; + + if ((b + certDataSize + 2) > eof) // certificate length + 2 bytes for trust flags + break; + Certificate c; + if (c.decode(b, (unsigned int)certDataSize)) { + b += certDataSize; + this->add(c, Utils::loadBigEndian(b)); + b += 2; + + ++readCount; + } + } + + return readCount; +} + +} // namespace ZeroTier diff --git a/core/TrustStore.hpp b/core/TrustStore.hpp index 3585f1e87..155bad206 100644 --- a/core/TrustStore.hpp +++ b/core/TrustStore.hpp @@ -14,16 +14,16 @@ #ifndef ZT_TRUSTSTORE_HPP #define ZT_TRUSTSTORE_HPP -#include "Constants.hpp" -#include "Context.hpp" -#include "Containers.hpp" #include "Certificate.hpp" -#include "SHA512.hpp" -#include "SharedPtr.hpp" -#include "Identity.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Context.hpp" #include "Fingerprint.hpp" +#include "Identity.hpp" #include "Mutex.hpp" #include "Peer.hpp" +#include "SHA512.hpp" +#include "SharedPtr.hpp" namespace ZeroTier { @@ -43,176 +43,181 @@ namespace ZeroTier { * hence there are no methods for doing that. There's only one instance in a * node anyway. */ -class TrustStore -{ -public: - /** - * An entry in the node certificate trust store - */ - class Entry - { - friend class SharedPtr< TrustStore::Entry >; - friend class SharedPtr< const TrustStore::Entry >; - friend class TrustStore; +class TrustStore { + public: + /** + * An entry in the node certificate trust store + */ + class Entry { + friend class SharedPtr; + friend class SharedPtr; + friend class TrustStore; - public: - /** - * @return Reference to held certificate - */ - ZT_INLINE const Certificate &certificate() const noexcept - { return m_certificate; } + public: + /** + * @return Reference to held certificate + */ + ZT_INLINE const Certificate& certificate() const noexcept + { + return m_certificate; + } - /** - * Get the local trust for this certificate - * - * This value may be changed dynamically by calls to update(). - * - * @return Local trust bit mask - */ - ZT_INLINE unsigned int localTrust() const noexcept - { - RWMutex::RLock l(m_lock); - return m_localTrust; - } + /** + * Get the local trust for this certificate + * + * This value may be changed dynamically by calls to update(). + * + * @return Local trust bit mask + */ + ZT_INLINE unsigned int localTrust() const noexcept + { + RWMutex::RLock l(m_lock); + return m_localTrust; + } - /** - * Change the local trust of this entry - * - * @param lt New local trust bit mask - */ - ZT_INLINE void setLocalTrust(const unsigned int lt) noexcept - { - RWMutex::Lock l(m_lock); - m_localTrust = lt; - } + /** + * Change the local trust of this entry + * + * @param lt New local trust bit mask + */ + ZT_INLINE void setLocalTrust(const unsigned int lt) noexcept + { + RWMutex::Lock l(m_lock); + m_localTrust = lt; + } - /** - * Get the error code for this certificate - * - * @return Error or ZT_CERTIFICATE_ERROR_NONE if none - */ - ZT_INLINE ZT_CertificateError error() const noexcept - { - RWMutex::RLock l(m_lock); - return m_error; - } + /** + * Get the error code for this certificate + * + * @return Error or ZT_CERTIFICATE_ERROR_NONE if none + */ + ZT_INLINE ZT_CertificateError error() const noexcept + { + RWMutex::RLock l(m_lock); + return m_error; + } - private: - Entry &operator=(const Entry &) { return *this; } + private: + Entry& operator=(const Entry&) + { + return *this; + } - ZT_INLINE Entry(RWMutex &l, const Certificate &cert, const unsigned int lt) noexcept: - __refCount(0), - m_lock(l), - m_certificate(cert), - m_localTrust(lt), - m_error(ZT_CERTIFICATE_ERROR_NONE), - m_subjectDeprecated(false), - m_onTrustPath(false) - {} + ZT_INLINE Entry(RWMutex& l, const Certificate& cert, const unsigned int lt) noexcept + : __refCount(0) + , m_lock(l) + , m_certificate(cert) + , m_localTrust(lt) + , m_error(ZT_CERTIFICATE_ERROR_NONE) + , m_subjectDeprecated(false) + , m_onTrustPath(false) + { + } - std::atomic< int > __refCount; + std::atomic __refCount; - RWMutex &m_lock; - const Certificate m_certificate; - unsigned int m_localTrust; - ZT_CertificateError m_error; - bool m_subjectDeprecated; - bool m_onTrustPath; - }; + RWMutex& m_lock; + const Certificate m_certificate; + unsigned int m_localTrust; + ZT_CertificateError m_error; + bool m_subjectDeprecated; + bool m_onTrustPath; + }; - TrustStore(); - ~TrustStore(); + TrustStore(); + ~TrustStore(); - /** - * Get certificate by certificate serial number - * - * Note that the error code should be checked. The certificate may be - * rejected and may still be in the store unless the store has been - * purged. - * - * @param serial SHA384 hash of certificate - * @return Entry or empty/nil if not found - */ - SharedPtr< Entry > get(const H384 &serial) const; + /** + * Get certificate by certificate serial number + * + * Note that the error code should be checked. The certificate may be + * rejected and may still be in the store unless the store has been + * purged. + * + * @param serial SHA384 hash of certificate + * @return Entry or empty/nil if not found + */ + SharedPtr get(const H384& serial) const; - /** - * Get roots specified by root set certificates in the local store. - * - * If more than one certificate locally trusted as a root set specifies - * the root, it will be returned once (as per Map behavior) but the latest - * locator will be returned from among those available. - * - * @return Roots and the latest locator specified for each (if any) - */ - Map< Identity, SharedPtr< const Locator > > roots(); + /** + * Get roots specified by root set certificates in the local store. + * + * If more than one certificate locally trusted as a root set specifies + * the root, it will be returned once (as per Map behavior) but the latest + * locator will be returned from among those available. + * + * @return Roots and the latest locator specified for each (if any) + */ + Map > roots(); - /** - * @param includeRejectedCertificates If true, also include certificates with error codes - * @return All certificates in asecending sort order by serial - */ - Vector< SharedPtr< Entry > > all(bool includeRejectedCertificates) const; + /** + * @param includeRejectedCertificates If true, also include certificates with error codes + * @return All certificates in asecending sort order by serial + */ + Vector > all(bool includeRejectedCertificates) const; - /** - * Add a certificate - * - * A copy is made so it's fine if the original is freed after this call. If - * the certificate already exists its local trust flags are updated. - * - * IMPORTANT: The caller MUST also call update() after calling add() one or - * more times to actually add and revalidate certificates and their signature - * chains. - * - * @param cert Certificate to add - */ - void add(const Certificate &cert, unsigned int localTrust); + /** + * Add a certificate + * + * A copy is made so it's fine if the original is freed after this call. If + * the certificate already exists its local trust flags are updated. + * + * IMPORTANT: The caller MUST also call update() after calling add() one or + * more times to actually add and revalidate certificates and their signature + * chains. + * + * @param cert Certificate to add + */ + void add(const Certificate& cert, unsigned int localTrust); - /** - * Queue a certificate to be deleted - * - * Actual delete does not happen until the next update(). - * - * @param serial Serial of certificate to delete - */ - void erase(const H384 &serial); + /** + * Queue a certificate to be deleted + * + * Actual delete does not happen until the next update(). + * + * @param serial Serial of certificate to delete + */ + void erase(const H384& serial); - /** - * Validate all certificates and their certificate chains - * - * This also processes any certificates added with add() since the last call to update(). - * - * @param clock Current time in milliseconds since epoch, or -1 to not check times on this pass - * @param purge If non-NULL, purge rejected certificates and return them in this vector (vector should be empty) - * @return True if there were changes - */ - bool update(int64_t clock, Vector< SharedPtr< Entry > > *purge); + /** + * Validate all certificates and their certificate chains + * + * This also processes any certificates added with add() since the last call to update(). + * + * @param clock Current time in milliseconds since epoch, or -1 to not check times on this pass + * @param purge If non-NULL, purge rejected certificates and return them in this vector (vector should be empty) + * @return True if there were changes + */ + bool update(int64_t clock, Vector >* purge); - /** - * Create a compressed binary version of certificates and their local trust - * - * @return Binary compressed certificates and local trust info - */ - Vector< uint8_t > save() const; + /** + * Create a compressed binary version of certificates and their local trust + * + * @return Binary compressed certificates and local trust info + */ + Vector save() const; - /** - * Decode a saved trust store - * - * Decoded certificates are added to the add queue, so update() must be - * called after this to actually apply them. - * - * @param data Data to decode - * @return Number of certificates or -1 if input is invalid - */ - int load(const Vector< uint8_t > &data); + /** + * Decode a saved trust store + * + * Decoded certificates are added to the add queue, so update() must be + * called after this to actually apply them. + * + * @param data Data to decode + * @return Number of certificates or -1 if input is invalid + */ + int load(const Vector& data); -private: - Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates - Map< Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only - Map< Fingerprint, Vector< SharedPtr< Entry > > > m_bySubjectIdentity; // non-rejected certificates only - ForwardList< SharedPtr< Entry > > m_addQueue; - ForwardList< H384 > m_deleteQueue; - RWMutex m_lock; + private: + Map > m_bySerial; // all certificates + Map, SharedPtr > + m_bySubjectUniqueId; // non-rejected certificates only + Map > > m_bySubjectIdentity; // non-rejected certificates only + ForwardList > m_addQueue; + ForwardList m_deleteQueue; + RWMutex m_lock; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/Utils.cpp b/core/Utils.cpp index 9d6c6f05b..29f7d8d37 100644 --- a/core/Utils.cpp +++ b/core/Utils.cpp @@ -12,16 +12,17 @@ /****/ #include "Utils.hpp" -#include "Mutex.hpp" + #include "AES.hpp" +#include "Mutex.hpp" #include "SHA512.hpp" #include #ifdef __UNIX_LIKE__ -#include #include #include +#include #endif #ifdef __WINDOWS__ @@ -32,8 +33,8 @@ #ifdef ZT_ARCH_ARM_HAS_NEON #ifdef __LINUX__ -#include #include +#include #endif #if defined(__FreeBSD__) @@ -41,9 +42,9 @@ #include static inline long getauxval(int caps) { - long hwcaps = 0; - elf_aux_info(caps, &hwcaps, sizeof(hwcaps)); - return hwcaps; + long hwcaps = 0; + elf_aux_info(caps, &hwcaps, sizeof(hwcaps)); + return hwcaps; } #endif @@ -73,41 +74,40 @@ namespace Utils { #ifdef ZT_ARCH_ARM_HAS_NEON ARMCapabilities::ARMCapabilities() noexcept { - #ifdef __APPLE__ - this->aes = true; - this->crc32 = true; - this->pmull = true; - this->sha1 = true; - this->sha2 = true; + this->aes = true; + this->crc32 = true; + this->pmull = true; + this->sha1 = true; + this->sha2 = true; #else #ifdef __LINUX__ #ifdef HWCAP2_AES - if (sizeof(void *) == 4) { - const long hwcaps2 = getauxval(AT_HWCAP2); - this->aes = (hwcaps2 & HWCAP2_AES) != 0; - this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; - this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; - this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; - this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; - } else { + if (sizeof(void*) == 4) { + const long hwcaps2 = getauxval(AT_HWCAP2); + this->aes = (hwcaps2 & HWCAP2_AES) != 0; + this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; + this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; + this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; + this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; + } + else { #endif - const long hwcaps = getauxval(AT_HWCAP); - this->aes = (hwcaps & HWCAP_AES) != 0; - this->crc32 = (hwcaps & HWCAP_CRC32) != 0; - this->pmull = (hwcaps & HWCAP_PMULL) != 0; - this->sha1 = (hwcaps & HWCAP_SHA1) != 0; - this->sha2 = (hwcaps & HWCAP_SHA2) != 0; + const long hwcaps = getauxval(AT_HWCAP); + this->aes = (hwcaps & HWCAP_AES) != 0; + this->crc32 = (hwcaps & HWCAP_CRC32) != 0; + this->pmull = (hwcaps & HWCAP_PMULL) != 0; + this->sha1 = (hwcaps & HWCAP_SHA1) != 0; + this->sha2 = (hwcaps & HWCAP_SHA2) != 0; #ifdef HWCAP2_AES - } + } #endif #endif #endif - } const ARMCapabilities ARMCAP; @@ -116,47 +116,39 @@ const ARMCapabilities ARMCAP; #ifdef ZT_ARCH_X64 CPUIDRegisters::CPUIDRegisters() noexcept { - uint32_t eax, ebx, ecx, edx; + uint32_t eax, ebx, ecx, edx; #ifdef __WINDOWS__ - int regs[4]; - __cpuid(regs,1); - eax = (uint32_t)regs[0]; - ebx = (uint32_t)regs[1]; - ecx = (uint32_t)regs[2]; - edx = (uint32_t)regs[3]; + int regs[4]; + __cpuid(regs, 1); + eax = (uint32_t)regs[0]; + ebx = (uint32_t)regs[1]; + ecx = (uint32_t)regs[2]; + edx = (uint32_t)regs[3]; #else - __asm__ __volatile__ ( - "cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(1), "c"(0) - ); + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0)); #endif - rdrand = ((ecx & (1U << 30U)) != 0); - aes = (((ecx & (1U << 25U)) != 0) && ((ecx & (1U << 19U)) != 0) && ((ecx & (1U << 1U)) != 0)); - avx = ((ecx & (1U << 25U)) != 0); + rdrand = ((ecx & (1U << 30U)) != 0); + aes = (((ecx & (1U << 25U)) != 0) && ((ecx & (1U << 19U)) != 0) && ((ecx & (1U << 1U)) != 0)); + avx = ((ecx & (1U << 25U)) != 0); #ifdef __WINDOWS__ - __cpuid(regs,7); - eax = (uint32_t)regs[0]; - ebx = (uint32_t)regs[1]; - ecx = (uint32_t)regs[2]; - edx = (uint32_t)regs[3]; + __cpuid(regs, 7); + eax = (uint32_t)regs[0]; + ebx = (uint32_t)regs[1]; + ecx = (uint32_t)regs[2]; + edx = (uint32_t)regs[3]; #else - __asm__ __volatile__ ( - "cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(7), "c"(0) - ); + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0)); #endif - vaes = aes && avx && ((ecx & (1U << 9U)) != 0); - vpclmulqdq = aes && avx && ((ecx & (1U << 10U)) != 0); - avx2 = avx && ((ebx & (1U << 5U)) != 0); - avx512f = avx && ((ebx & (1U << 16U)) != 0); - sha = ((ebx & (1U << 29U)) != 0); - fsrm = ((edx & (1U << 4U)) != 0); + vaes = aes && avx && ((ecx & (1U << 9U)) != 0); + vpclmulqdq = aes && avx && ((ecx & (1U << 10U)) != 0); + avx2 = avx && ((ebx & (1U << 5U)) != 0); + avx512f = avx && ((ebx & (1U << 16U)) != 0); + sha = ((ebx & (1U << 29U)) != 0); + fsrm = ((edx & (1U << 4U)) != 0); } const CPUIDRegisters CPUID; @@ -164,379 +156,391 @@ const CPUIDRegisters CPUID; const std::bad_alloc BadAllocException; const std::out_of_range OutOfRangeException("access out of range"); -const uint64_t ZERO256[4] = {0, 0, 0, 0}; -const char HEXCHARS[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; +const uint64_t ZERO256[4] = { 0, 0, 0, 0 }; +const char HEXCHARS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; const uint64_t s_mapNonce = getSecureRandomU64(); -bool secureEq(const void *const a, const void *const b, const unsigned int len) noexcept +bool secureEq(const void* const a, const void* const b, const unsigned int len) noexcept { - uint8_t diff = 0; - for (unsigned int i = 0; i < len; ++i) - diff |= ((reinterpret_cast(a))[i] ^ (reinterpret_cast(b))[i]); - return (diff == 0); + uint8_t diff = 0; + for (unsigned int i = 0; i < len; ++i) + diff |= ((reinterpret_cast(a))[i] ^ (reinterpret_cast(b))[i]); + return (diff == 0); } -void burn(volatile void *const ptr, const unsigned int len) +void burn(volatile void* const ptr, const unsigned int len) { - static volatile uintptr_t foo = 0; - Utils::zero((void *)ptr, len); - // Force compiler not to optimize this function out by taking a volatile - // parameter and also updating a volatile variable. - foo += (uintptr_t)len ^ (uintptr_t)reinterpret_cast(ptr)[0]; + static volatile uintptr_t foo = 0; + Utils::zero((void*)ptr, len); + // Force compiler not to optimize this function out by taking a volatile + // parameter and also updating a volatile variable. + foo += (uintptr_t)len ^ (uintptr_t) reinterpret_cast(ptr)[0]; } -static unsigned long s_decimalRecursive(unsigned long n, char *s) +static unsigned long s_decimalRecursive(unsigned long n, char* s) { - if (n == 0) - return 0; - unsigned long pos = s_decimalRecursive(n / 10, s); - if (pos >= 22) // sanity check,should be impossible - pos = 22; - s[pos] = (char)('0' + (n % 10)); - return pos + 1; + if (n == 0) + return 0; + unsigned long pos = s_decimalRecursive(n / 10, s); + if (pos >= 22) // sanity check,should be impossible + pos = 22; + s[pos] = (char)('0' + (n % 10)); + return pos + 1; } -char *decimal(unsigned long n, char s[24]) noexcept +char* decimal(unsigned long n, char s[24]) noexcept { - if (n == 0) { - s[0] = '0'; - s[1] = (char)0; - return s; - } - s[s_decimalRecursive(n, s)] = (char)0; - return s; + if (n == 0) { + s[0] = '0'; + s[1] = (char)0; + return s; + } + s[s_decimalRecursive(n, s)] = (char)0; + return s; } -char *hex(uint64_t i, char buf[17]) noexcept +char* hex(uint64_t i, char buf[17]) noexcept { - if (i != 0) { - char *p = nullptr; - for (int b = 60; b >= 0; b -= 4) { - const unsigned int nyb = (unsigned int)(i >> (unsigned int)b) & 0xfU; - if (p) { - *(p++) = HEXCHARS[nyb]; - } else if (nyb != 0) { - p = buf; - *(p++) = HEXCHARS[nyb]; - } - } - *p = 0; - return buf; - } else { - buf[0] = '0'; - buf[1] = 0; - return buf; - } + if (i != 0) { + char* p = nullptr; + for (int b = 60; b >= 0; b -= 4) { + const unsigned int nyb = (unsigned int)(i >> (unsigned int)b) & 0xfU; + if (p) { + *(p++) = HEXCHARS[nyb]; + } + else if (nyb != 0) { + p = buf; + *(p++) = HEXCHARS[nyb]; + } + } + *p = 0; + return buf; + } + else { + buf[0] = '0'; + buf[1] = 0; + return buf; + } } -uint64_t unhex(const char *s) noexcept +uint64_t unhex(const char* s) noexcept { - uint64_t n = 0; - if (s) { - int k = 0; - while (k < 16) { - char hc = *(s++); - if (!hc) break; + uint64_t n = 0; + if (s) { + int k = 0; + while (k < 16) { + char hc = *(s++); + if (! hc) + break; - uint8_t c = 0; - if ((hc >= 48) && (hc <= 57)) - c = (uint8_t)hc - 48; - else if ((hc >= 97) && (hc <= 102)) - c = (uint8_t)hc - 87; - else if ((hc >= 65) && (hc <= 70)) - c = (uint8_t)hc - 55; + uint8_t c = 0; + if ((hc >= 48) && (hc <= 57)) + c = (uint8_t)hc - 48; + else if ((hc >= 97) && (hc <= 102)) + c = (uint8_t)hc - 87; + else if ((hc >= 65) && (hc <= 70)) + c = (uint8_t)hc - 55; - n <<= 4U; - n |= (uint64_t)c; - ++k; - } - } - return n; + n <<= 4U; + n |= (uint64_t)c; + ++k; + } + } + return n; } -char *hex(const void *d, unsigned int l, char *s) noexcept +char* hex(const void* d, unsigned int l, char* s) noexcept { - char *const save = s; - for (unsigned int i = 0; i < l; ++i) { - const unsigned int b = reinterpret_cast(d)[i]; - *(s++) = HEXCHARS[b >> 4U]; - *(s++) = HEXCHARS[b & 0xfU]; - } - *s = (char)0; - return save; + char* const save = s; + for (unsigned int i = 0; i < l; ++i) { + const unsigned int b = reinterpret_cast(d)[i]; + *(s++) = HEXCHARS[b >> 4U]; + *(s++) = HEXCHARS[b & 0xfU]; + } + *s = (char)0; + return save; } -unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buflen) noexcept +unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen) noexcept { - unsigned int l = 0; - const char *hend = h + hlen; - while (l < buflen) { - if (h == hend) break; - uint8_t hc = *(reinterpret_cast(h++)); - if (!hc) break; + unsigned int l = 0; + const char* hend = h + hlen; + while (l < buflen) { + if (h == hend) + break; + uint8_t hc = *(reinterpret_cast(h++)); + if (! hc) + break; - uint8_t c = 0; - if ((hc >= 48) && (hc <= 57)) - c = hc - 48; - else if ((hc >= 97) && (hc <= 102)) - c = hc - 87; - else if ((hc >= 65) && (hc <= 70)) - c = hc - 55; + uint8_t c = 0; + if ((hc >= 48) && (hc <= 57)) + c = hc - 48; + else if ((hc >= 97) && (hc <= 102)) + c = hc - 87; + else if ((hc >= 65) && (hc <= 70)) + c = hc - 55; - if (h == hend) break; - hc = *(reinterpret_cast(h++)); - if (!hc) break; + if (h == hend) + break; + hc = *(reinterpret_cast(h++)); + if (! hc) + break; - c <<= 4U; - if ((hc >= 48) && (hc <= 57)) - c |= hc - 48; - else if ((hc >= 97) && (hc <= 102)) - c |= hc - 87; - else if ((hc >= 65) && (hc <= 70)) - c |= hc - 55; + c <<= 4U; + if ((hc >= 48) && (hc <= 57)) + c |= hc - 48; + else if ((hc >= 97) && (hc <= 102)) + c |= hc - 87; + else if ((hc >= 65) && (hc <= 70)) + c |= hc - 55; - reinterpret_cast(buf)[l++] = c; - } - return l; + reinterpret_cast(buf)[l++] = c; + } + return l; } -#define ZT_GETSECURERANDOM_STATE_SIZE 64 +#define ZT_GETSECURERANDOM_STATE_SIZE 64 #define ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR 1048576 -void getSecureRandom(void *const buf, unsigned int bytes) noexcept +void getSecureRandom(void* const buf, unsigned int bytes) noexcept { - static Mutex globalLock; - static bool initialized = false; - static uint64_t randomState[ZT_GETSECURERANDOM_STATE_SIZE]; - static unsigned int randomByteCounter = ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR; // init on first run - static AES randomGen; + static Mutex globalLock; + static bool initialized = false; + static uint64_t randomState[ZT_GETSECURERANDOM_STATE_SIZE]; + static unsigned int randomByteCounter = ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR; // init on first run + static AES randomGen; - Mutex::Lock gl(globalLock); + Mutex::Lock gl(globalLock); - // Re-initialize the PRNG every ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR bytes. Note that - // if 'bytes' is larger than ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR we can generate more - // than this, but this isn't an issue. ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR could be - // much larger if we wanted and this would still be safe. - randomByteCounter += bytes; - if (unlikely(randomByteCounter >= ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR)) { - randomByteCounter = 0; + // Re-initialize the PRNG every ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR bytes. Note that + // if 'bytes' is larger than ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR we can generate more + // than this, but this isn't an issue. ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR could be + // much larger if we wanted and this would still be safe. + randomByteCounter += bytes; + if (unlikely(randomByteCounter >= ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR)) { + randomByteCounter = 0; - if (unlikely(!initialized)) { - initialized = true; - Utils::zero< sizeof(randomState) >(randomState); + if (unlikely(! initialized)) { + initialized = true; + Utils::zero(randomState); #ifdef __WINDOWS__ - HCRYPTPROV cryptProvider = NULL; - if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { - fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); - exit(1); - } - if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomState),(BYTE *)randomState)) { - fprintf(stderr,"FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); - exit(1); - } - CryptReleaseContext(cryptProvider,0); + HCRYPTPROV cryptProvider = NULL; + if (! CryptAcquireContextA(&cryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); + exit(1); + } + if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomState), (BYTE*)randomState)) { + fprintf(stderr, "FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); + exit(1); + } + CryptReleaseContext(cryptProvider, 0); #else - int devURandomFd = ::open("/dev/urandom", O_RDONLY); - if (devURandomFd < 0) { - fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n"); - exit(1); - } - if ((long)::read(devURandomFd, randomState, sizeof(randomState)) != (long)sizeof(randomState)) { - ::close(devURandomFd); - fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n"); - exit(1); - } - close(devURandomFd); + int devURandomFd = ::open("/dev/urandom", O_RDONLY); + if (devURandomFd < 0) { + fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n"); + exit(1); + } + if ((long)::read(devURandomFd, randomState, sizeof(randomState)) != (long)sizeof(randomState)) { + ::close(devURandomFd); + fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n"); + exit(1); + } + close(devURandomFd); #endif #ifdef __UNIX_LIKE__ - randomState[0] += (uint64_t)getpid(); - randomState[1] += (uint64_t)getppid(); + randomState[0] += (uint64_t)getpid(); + randomState[1] += (uint64_t)getppid(); #endif #ifdef ZT_ARCH_X64 - if (CPUID.rdrand) { - uint64_t tmp = 0; - for (unsigned long i = 0; i < ZT_GETSECURERANDOM_STATE_SIZE; ++i) { - _rdrand64_step((unsigned long long *)&tmp); - randomState[i] ^= tmp; - } - } + if (CPUID.rdrand) { + uint64_t tmp = 0; + for (unsigned long i = 0; i < ZT_GETSECURERANDOM_STATE_SIZE; ++i) { + _rdrand64_step((unsigned long long*)&tmp); + randomState[i] ^= tmp; + } + } #endif - } + } - // Initialize or re-initialize generator by hashing the full state, - // replacing the first 64 bytes with this hash, and then re-initializing - // AES with the first 32 bytes. - randomState[0] += (uint64_t)time(nullptr); - SHA512(randomState, randomState, sizeof(randomState)); - randomGen.init(randomState); - } + // Initialize or re-initialize generator by hashing the full state, + // replacing the first 64 bytes with this hash, and then re-initializing + // AES with the first 32 bytes. + randomState[0] += (uint64_t)time(nullptr); + SHA512(randomState, randomState, sizeof(randomState)); + randomGen.init(randomState); + } - // Generate random bytes using AES and bytes 32-48 of randomState as an in-place - // AES-CTR counter. Counter can be machine endian; we don't care about portability - // for a random generator. - uint64_t *const ctr = randomState + 4; - uint8_t *out = reinterpret_cast(buf); + // Generate random bytes using AES and bytes 32-48 of randomState as an in-place + // AES-CTR counter. Counter can be machine endian; we don't care about portability + // for a random generator. + uint64_t* const ctr = randomState + 4; + uint8_t* out = reinterpret_cast(buf); - while (bytes >= 16) { - ++*ctr; - randomGen.encrypt(ctr, out); - out += 16; - bytes -= 16; - } + while (bytes >= 16) { + ++*ctr; + randomGen.encrypt(ctr, out); + out += 16; + bytes -= 16; + } - if (bytes > 0) { - uint8_t tmp[16]; - ++*ctr; - randomGen.encrypt(ctr, tmp); - for (unsigned int i = 0; i < bytes; ++i) - out[i] = tmp[i]; - Utils::burn(tmp, sizeof(tmp)); // don't leave used cryptographic randomness lying around! - } + if (bytes > 0) { + uint8_t tmp[16]; + ++*ctr; + randomGen.encrypt(ctr, tmp); + for (unsigned int i = 0; i < bytes; ++i) + out[i] = tmp[i]; + Utils::burn(tmp, sizeof(tmp)); // don't leave used cryptographic randomness lying around! + } } uint64_t getSecureRandomU64() noexcept { - uint64_t tmp; - getSecureRandom(&tmp, sizeof(tmp)); - return tmp; + uint64_t tmp; + getSecureRandom(&tmp, sizeof(tmp)); + return tmp; } -int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept +int b32e(const uint8_t* data, int length, char* result, int bufSize) noexcept { - if (length < 0 || length > (1 << 28U)) { - result[0] = (char)0; - return -1; - } - int count = 0; - if (length > 0) { - int buffer = data[0]; - int next = 1; - int bitsLeft = 8; - while (count < bufSize && (bitsLeft > 0 || next < length)) { - if (bitsLeft < 5) { - if (next < length) { - buffer <<= 8U; - buffer |= data[next++] & 0xffU; - bitsLeft += 8; - } else { - int pad = 5 - bitsLeft; - buffer <<= pad; - bitsLeft += pad; - } - } - int index = 0x1f & (buffer >> (unsigned int)(bitsLeft - 5)); - bitsLeft -= 5; - result[count++] = "abcdefghijklmnopqrstuvwxyz234567"[index]; - } - } - if (count < bufSize) { - result[count] = (char)0; - return count; - } - result[0] = (char)0; - return -1; + if (length < 0 || length > (1 << 28U)) { + result[0] = (char)0; + return -1; + } + int count = 0; + if (length > 0) { + int buffer = data[0]; + int next = 1; + int bitsLeft = 8; + while (count < bufSize && (bitsLeft > 0 || next < length)) { + if (bitsLeft < 5) { + if (next < length) { + buffer <<= 8U; + buffer |= data[next++] & 0xffU; + bitsLeft += 8; + } + else { + int pad = 5 - bitsLeft; + buffer <<= pad; + bitsLeft += pad; + } + } + int index = 0x1f & (buffer >> (unsigned int)(bitsLeft - 5)); + bitsLeft -= 5; + result[count++] = "abcdefghijklmnopqrstuvwxyz234567"[index]; + } + } + if (count < bufSize) { + result[count] = (char)0; + return count; + } + result[0] = (char)0; + return -1; } -int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept +int b32d(const char* encoded, uint8_t* result, int bufSize) noexcept { - int buffer = 0; - int bitsLeft = 0; - int count = 0; - for (const uint8_t *ptr = (const uint8_t *)encoded; count < bufSize && *ptr; ++ptr) { - uint8_t ch = *ptr; - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '.') { - continue; - } - buffer <<= 5; + int buffer = 0; + int bitsLeft = 0; + int count = 0; + for (const uint8_t* ptr = (const uint8_t*)encoded; count < bufSize && *ptr; ++ptr) { + uint8_t ch = *ptr; + if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '.') { + continue; + } + buffer <<= 5; - if (ch == '0') { - ch = 'O'; - } else if (ch == '1') { - ch = 'L'; - } else if (ch == '8') { - ch = 'B'; - } + if (ch == '0') { + ch = 'O'; + } + else if (ch == '1') { + ch = 'L'; + } + else if (ch == '8') { + ch = 'B'; + } - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { - ch = (ch & 0x1f) - 1; - } else if (ch >= '2' && ch <= '7') { - ch -= '2' - 26; - } else { - return -1; - } + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { + ch = (ch & 0x1f) - 1; + } + else if (ch >= '2' && ch <= '7') { + ch -= '2' - 26; + } + else { + return -1; + } - buffer |= ch; - bitsLeft += 5; - if (bitsLeft >= 8) { - result[count++] = buffer >> (bitsLeft - 8); - bitsLeft -= 8; - } - } - if (count < bufSize) - result[count] = (uint8_t)0; - return count; + buffer |= ch; + bitsLeft += 5; + if (bitsLeft >= 8) { + result[count++] = buffer >> (bitsLeft - 8); + bitsLeft -= 8; + } + } + if (count < bufSize) + result[count] = (uint8_t)0; + return count; } uint64_t random() noexcept { - static volatile uint64_t s_s0 = getSecureRandomU64(); - static volatile uint64_t s_s1 = getSecureRandomU64(); - static volatile uint64_t s_s2 = getSecureRandomU64(); - static volatile uint64_t s_s3 = getSecureRandomU64(); + static volatile uint64_t s_s0 = getSecureRandomU64(); + static volatile uint64_t s_s1 = getSecureRandomU64(); + static volatile uint64_t s_s2 = getSecureRandomU64(); + static volatile uint64_t s_s3 = getSecureRandomU64(); - // https://en.wikipedia.org/wiki/Xorshift#xoshiro256** - uint64_t s0 = s_s0; - uint64_t s1 = s_s1; - uint64_t s2 = s_s2; - uint64_t s3 = s_s3; - const uint64_t s1x5 = s1 * 5ULL; - const uint64_t result = ((s1x5 << 7U) | (s1x5 >> 57U)) * 9ULL; - const uint64_t t = s1 << 17U; - s2 ^= s0; - s3 ^= s1; - s1 ^= s2; - s0 ^= s3; - s2 ^= t; - s3 = ((s3 << 45U) | (s3 >> 19U)); - s_s0 = s0; - s_s1 = s1; - s_s2 = s2; - s_s3 = s3; + // https://en.wikipedia.org/wiki/Xorshift#xoshiro256** + uint64_t s0 = s_s0; + uint64_t s1 = s_s1; + uint64_t s2 = s_s2; + uint64_t s3 = s_s3; + const uint64_t s1x5 = s1 * 5ULL; + const uint64_t result = ((s1x5 << 7U) | (s1x5 >> 57U)) * 9ULL; + const uint64_t t = s1 << 17U; + s2 ^= s0; + s3 ^= s1; + s1 ^= s2; + s0 ^= s3; + s2 ^= t; + s3 = ((s3 << 45U) | (s3 >> 19U)); + s_s0 = s0; + s_s1 = s1; + s_s2 = s2; + s_s3 = s3; - return result; + return result; } -bool scopy(char *const dest, const unsigned int len, const char *const src) noexcept +bool scopy(char* const dest, const unsigned int len, const char* const src) noexcept { - if (unlikely((len == 0)||(dest == nullptr))) { - return false; - } - if (unlikely(src == nullptr)) { - *dest = (char)0; - return true; - } - unsigned int i = 0; - for (;;) { - if (i >= len) { - dest[len - 1] = 0; - return false; - } - if ((dest[i] = src[i]) == 0) { - return true; - } - ++i; - } + if (unlikely((len == 0) || (dest == nullptr))) { + return false; + } + if (unlikely(src == nullptr)) { + *dest = (char)0; + return true; + } + unsigned int i = 0; + for (;;) { + if (i >= len) { + dest[len - 1] = 0; + return false; + } + if ((dest[i] = src[i]) == 0) { + return true; + } + ++i; + } } -uint32_t fnv1a32(const void *const restrict data, const unsigned int len) noexcept +uint32_t fnv1a32(const void* const restrict data, const unsigned int len) noexcept { - uint32_t h = 0x811c9dc5; - const uint32_t p = 0x01000193; - for (unsigned int i = 0; i < len; ++i) - h = (h ^ (uint32_t)reinterpret_cast(data)[i]) * p; - return h; + uint32_t h = 0x811c9dc5; + const uint32_t p = 0x01000193; + for (unsigned int i = 0; i < len; ++i) + h = (h ^ (uint32_t) reinterpret_cast(data)[i]) * p; + return h; } -} // namespace Utils +} // namespace Utils -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/Utils.hpp b/core/Utils.hpp index 4139ad45f..520d32251 100644 --- a/core/Utils.hpp +++ b/core/Utils.hpp @@ -16,13 +16,12 @@ #include "Constants.hpp" -#include -#include - -#include #include #include +#include +#include #include +#include namespace ZeroTier { @@ -37,15 +36,11 @@ namespace Utils { // Macros to convert endian-ness at compile time for constants. #if __BYTE_ORDER == __LITTLE_ENDIAN #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U))) -#define ZT_CONST_TO_BE_UINT64(x) ( \ - (((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \ - (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \ - (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \ - (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \ - (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \ - (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \ - (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \ - (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U)) +#define ZT_CONST_TO_BE_UINT64(x) \ + ((((uint64_t)(x)&0x00000000000000ffULL) << 56U) | (((uint64_t)(x)&0x000000000000ff00ULL) << 40U) \ + | (((uint64_t)(x)&0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x)&0x00000000ff000000ULL) << 8U) \ + | (((uint64_t)(x)&0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24U) \ + | (((uint64_t)(x)&0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x)&0xff00000000000000ULL) >> 56U)) #else #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x)) #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x)) @@ -57,19 +52,17 @@ namespace Utils { #define ZT_ROL32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) #ifdef ZT_ARCH_ARM_HAS_NEON -struct ARMCapabilities -{ - ARMCapabilities() noexcept; - bool aes, crc32, pmull, sha1, sha2; +struct ARMCapabilities { + ARMCapabilities() noexcept; + bool aes, crc32, pmull, sha1, sha2; }; extern const ARMCapabilities ARMCAP; #endif #ifdef ZT_ARCH_X64 -struct CPUIDRegisters -{ - CPUIDRegisters() noexcept; - bool rdrand, aes, avx, vaes, vpclmulqdq, avx2, avx512f, sha, fsrm; +struct CPUIDRegisters { + CPUIDRegisters() noexcept; + bool rdrand, aes, avx, vaes, vpclmulqdq, avx2, avx512f, sha, fsrm; }; extern const CPUIDRegisters CPUID; #endif @@ -100,7 +93,7 @@ extern const uint64_t s_mapNonce; * @param len Length of strings * @return True if strings are equal */ -bool secureEq(const void *a, const void *b, unsigned int len) noexcept; +bool secureEq(const void* a, const void* b, unsigned int len) noexcept; /** * Be absolutely sure to zero memory @@ -111,14 +104,14 @@ bool secureEq(const void *a, const void *b, unsigned int len) noexcept; * @param ptr Memory to zero * @param len Length of memory in bytes */ -void burn(volatile void *ptr, unsigned int len); +void burn(volatile void* ptr, unsigned int len); /** * @param n Number to convert * @param s Buffer, at least 24 bytes in size * @return String containing 'n' in base 10 form */ -char *decimal(unsigned long n, char s[24]) noexcept; +char* decimal(unsigned long n, char s[24]) noexcept; /** * Convert an unsigned integer into hex @@ -127,7 +120,7 @@ char *decimal(unsigned long n, char s[24]) noexcept; * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur. * @return Pointer to s containing hex string with trailing zero byte */ -char *hex(uint64_t i, char buf[17]) noexcept; +char* hex(uint64_t i, char buf[17]) noexcept; /** * Decode an unsigned integer in hex format @@ -135,7 +128,7 @@ char *hex(uint64_t i, char buf[17]) noexcept; * @param s String to decode, non-hex chars are ignored * @return Unsigned integer */ -uint64_t unhex(const char *s) noexcept; +uint64_t unhex(const char* s) noexcept; /** * Convert a byte array into hex @@ -145,7 +138,7 @@ uint64_t unhex(const char *s) noexcept; * @param s String buffer, must be at least (l*2)+1 in size or overflow will occur * @return Pointer to filled string buffer */ -char *hex(const void *d, unsigned int l, char *s) noexcept; +char* hex(const void* d, unsigned int l, char* s) noexcept; /** * Decode a hex string @@ -156,7 +149,7 @@ char *hex(const void *d, unsigned int l, char *s) noexcept; * @param buflen Length of output buffer * @return Number of written bytes */ -unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buflen) noexcept; +unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen) noexcept; /** * Generate secure random bytes @@ -167,7 +160,7 @@ unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buf * @param buf Buffer to fill * @param bytes Number of random bytes to generate */ -void getSecureRandom(void *buf, unsigned int bytes) noexcept; +void getSecureRandom(void* buf, unsigned int bytes) noexcept; /** * @return Secure random 64-bit integer @@ -183,7 +176,7 @@ uint64_t getSecureRandomU64() noexcept; * @param bufSize Size of result buffer * @return Number of bytes written */ -int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept; +int b32e(const uint8_t* data, int length, char* result, int bufSize) noexcept; /** * Decode base32 string @@ -193,7 +186,7 @@ int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept; * @param bufSize Size of result buffer * @return Number of bytes written or -1 on error */ -int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept; +int b32d(const char* encoded, uint8_t* result, int bufSize) noexcept; /** * Get a non-cryptographic random integer. @@ -215,18 +208,18 @@ uint64_t random() noexcept; * @param src Source string (if NULL, dest will receive a zero-length string and true is returned) * @return True on success, false on overflow (buffer will still be 0-terminated) */ -bool scopy(char *dest, unsigned int len, const char *src) noexcept; +bool scopy(char* dest, unsigned int len, const char* src) noexcept; /** * Check if a buffer's contents are all zero */ -static ZT_INLINE bool allZero(const void *const b, const unsigned int l) noexcept +static ZT_INLINE bool allZero(const void* const b, const unsigned int l) noexcept { - for (unsigned int i=0;i(b)[i] != 0) - return false; - } - return true; + for (unsigned int i = 0; i < l; ++i) { + if (reinterpret_cast(b)[i] != 0) + return false; + } + return true; } /** @@ -237,50 +230,59 @@ static ZT_INLINE bool allZero(const void *const b, const unsigned int l) noexcep * @param saveptr Pointer to pointer where function can save state * @return Next token or NULL if none */ -static ZT_INLINE char *stok(char *str, const char *delim, char **saveptr) noexcept +static ZT_INLINE char* stok(char* str, const char* delim, char** saveptr) noexcept { #ifdef __WINDOWS__ - return strtok_s(str, delim, saveptr); + return strtok_s(str, delim, saveptr); #else - return strtok_r(str, delim, saveptr); + return strtok_r(str, delim, saveptr); #endif } -static ZT_INLINE unsigned int strToUInt(const char *s) noexcept -{ return (unsigned int)strtoul(s, nullptr, 10); } +static ZT_INLINE unsigned int strToUInt(const char* s) noexcept +{ + return (unsigned int)strtoul(s, nullptr, 10); +} -static ZT_INLINE unsigned long long hexStrToU64(const char *s) noexcept +static ZT_INLINE unsigned long long hexStrToU64(const char* s) noexcept { #ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,nullptr,16); + return (unsigned long long)_strtoui64(s, nullptr, 16); #else - return strtoull(s, nullptr, 16); + return strtoull(s, nullptr, 16); #endif } #ifdef __GNUC__ static ZT_INLINE unsigned int countBits(const uint8_t v) noexcept -{ return (unsigned int)__builtin_popcount((unsigned int)v); } +{ + return (unsigned int)__builtin_popcount((unsigned int)v); +} static ZT_INLINE unsigned int countBits(const uint16_t v) noexcept -{ return (unsigned int)__builtin_popcount((unsigned int)v); } +{ + return (unsigned int)__builtin_popcount((unsigned int)v); +} static ZT_INLINE unsigned int countBits(const uint32_t v) noexcept -{ return (unsigned int)__builtin_popcountl((unsigned long)v); } +{ + return (unsigned int)__builtin_popcountl((unsigned long)v); +} static ZT_INLINE unsigned int countBits(const uint64_t v) noexcept -{ return (unsigned int)__builtin_popcountll((unsigned long long)v); } +{ + return (unsigned int)__builtin_popcountll((unsigned long long)v); +} #else -template -static ZT_INLINE unsigned int countBits(T v) noexcept +template static ZT_INLINE unsigned int countBits(T v) noexcept { - v = v - ((v >> 1) & (T)~(T)0/3); - v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); - v = (v + (v >> 4)) & (T)~(T)0/255*15; - return (unsigned int)((v * ((~((T)0))/((T)255))) >> ((sizeof(T) - 1) * 8)); + v = v - ((v >> 1) & (T) ~(T)0 / 3); + v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3); + v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15; + return (unsigned int)((v * ((~((T)0)) / ((T)255))) >> ((sizeof(T) - 1) * 8)); } #endif @@ -294,21 +296,15 @@ static ZT_INLINE unsigned int countBits(T v) noexcept static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept { #ifdef __GNUC__ - return __builtin_bswap64(n); + return __builtin_bswap64(n); #else #ifdef _MSC_VER - return (uint64_t)_byteswap_uint64((unsigned __int64)n); + return (uint64_t)_byteswap_uint64((unsigned __int64)n); #else - return ( - ((n & 0x00000000000000ffULL) << 56) | - ((n & 0x000000000000ff00ULL) << 40) | - ((n & 0x0000000000ff0000ULL) << 24) | - ((n & 0x00000000ff000000ULL) << 8) | - ((n & 0x000000ff00000000ULL) >> 8) | - ((n & 0x0000ff0000000000ULL) >> 24) | - ((n & 0x00ff000000000000ULL) >> 40) | - ((n & 0xff00000000000000ULL) >> 56) - ); + return ( + ((n & 0x00000000000000ffULL) << 56) | ((n & 0x000000000000ff00ULL) << 40) | ((n & 0x0000000000ff0000ULL) << 24) + | ((n & 0x00000000ff000000ULL) << 8) | ((n & 0x000000ff00000000ULL) >> 8) | ((n & 0x0000ff0000000000ULL) >> 24) + | ((n & 0x00ff000000000000ULL) >> 40) | ((n & 0xff00000000000000ULL) >> 56)); #endif #endif } @@ -322,12 +318,12 @@ static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept { #if defined(__GNUC__) - return __builtin_bswap32(n); + return __builtin_bswap32(n); #else #ifdef _MSC_VER - return (uint32_t)_byteswap_ulong((unsigned long)n); + return (uint32_t)_byteswap_ulong((unsigned long)n); #else - return htonl(n); + return htonl(n); #endif #endif } @@ -341,121 +337,120 @@ static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept { #if defined(__GNUC__) - return __builtin_bswap16(n); + return __builtin_bswap16(n); #else #ifdef _MSC_VER - return (uint16_t)_byteswap_ushort((unsigned short)n); + return (uint16_t)_byteswap_ushort((unsigned short)n); #else - return htons(n); + return htons(n); #endif #endif } // These are helper adapters to load and swap integer types special cased by size // to work with all typedef'd variants, signed/unsigned, etc. -template< typename I, unsigned int S > -class _swap_bytes_bysize; +template class _swap_bytes_bysize; -template< typename I > -class _swap_bytes_bysize< I, 1 > -{ -public: - static ZT_INLINE I s(const I n) noexcept - { return n; } +template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return n; + } }; -template< typename I > -class _swap_bytes_bysize< I, 2 > -{ -public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint16_t)n); } +template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint16_t)n); + } }; -template< typename I > -class _swap_bytes_bysize< I, 4 > -{ -public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint32_t)n); } +template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint32_t)n); + } }; -template< typename I > -class _swap_bytes_bysize< I, 8 > -{ -public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint64_t)n); } +template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint64_t)n); + } }; -template< typename I, unsigned int S > -class _load_be_bysize; +template class _load_be_bysize; -template< typename I > -class _load_be_bysize< I, 1 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return p[0]; } +template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return p[0]; + } }; -template< typename I > -class _load_be_bysize< I, 2 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); } +template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); + } }; -template< typename I > -class _load_be_bysize< I, 4 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); } +template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); + } }; -template< typename I > -class _load_be_bysize< I, 8 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); } +template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return ( + I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); + } }; -template< typename I, unsigned int S > -class _load_le_bysize; +template class _load_le_bysize; -template< typename I > -class _load_le_bysize< I, 1 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return p[0]; } +template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return p[0]; + } }; -template< typename I > -class _load_le_bysize< I, 2 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); } +template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); + } }; -template< typename I > -class _load_le_bysize< I, 4 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); } +template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); + } }; -template< typename I > -class _load_le_bysize< I, 8 > -{ -public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); } +template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return ( + I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); + } }; /** @@ -465,13 +460,12 @@ public: * @param n Value to convert * @return Value in big-endian order */ -template< typename I > -static ZT_INLINE I hton(const I n) noexcept +template static ZT_INLINE I hton(const I n) noexcept { #if __BYTE_ORDER == __LITTLE_ENDIAN - return _swap_bytes_bysize< I, sizeof(I) >::s(n); + return _swap_bytes_bysize::s(n); #else - return n; + return n; #endif } @@ -482,13 +476,12 @@ static ZT_INLINE I hton(const I n) noexcept * @param n Value to convert * @return Value in host byte order */ -template< typename I > -static ZT_INLINE I ntoh(const I n) noexcept +template static ZT_INLINE I ntoh(const I n) noexcept { #if __BYTE_ORDER == __LITTLE_ENDIAN - return _swap_bytes_bysize< I, sizeof(I) >::s(n); + return _swap_bytes_bysize::s(n); #else - return n; + return n; #endif } @@ -499,16 +492,15 @@ static ZT_INLINE I ntoh(const I n) noexcept * @param p Byte stream, must be at least sizeof(I) in size * @return Loaded raw integer */ -template< typename I > -static ZT_INLINE I loadMachineEndian(const void *const restrict p) noexcept +template static ZT_INLINE I loadMachineEndian(const void* const restrict p) noexcept { #ifdef ZT_NO_UNALIGNED_ACCESS - I tmp; - for(int i=0;i<(int)sizeof(I);++i) - reinterpret_cast(&tmp)[i] = reinterpret_cast(p)[i]; - return tmp; + I tmp; + for (int i = 0; i < (int)sizeof(I); ++i) + reinterpret_cast(&tmp)[i] = reinterpret_cast(p)[i]; + return tmp; #else - return *reinterpret_cast(p); + return *reinterpret_cast(p); #endif } @@ -519,14 +511,13 @@ static ZT_INLINE I loadMachineEndian(const void *const restrict p) noexcept * @param p Byte array (must be at least sizeof(I)) * @param i Integer to store */ -template< typename I > -static ZT_INLINE void storeMachineEndian(void *const restrict p, const I i) noexcept +template static ZT_INLINE void storeMachineEndian(void* const restrict p, const I i) noexcept { #ifdef ZT_NO_UNALIGNED_ACCESS - for(unsigned int k=0;k(p)[k] = reinterpret_cast(&i)[k]; + for (unsigned int k = 0; k < sizeof(I); ++k) + reinterpret_cast(p)[k] = reinterpret_cast(&i)[k]; #else - *reinterpret_cast(p) = i; + *reinterpret_cast(p) = i; #endif } @@ -537,13 +528,12 @@ static ZT_INLINE void storeMachineEndian(void *const restrict p, const I i) noex * @param p Byte stream, must be at least sizeof(I) in size * @return Decoded integer */ -template< typename I > -static ZT_INLINE I loadBigEndian(const void *const restrict p) noexcept +template static ZT_INLINE I loadBigEndian(const void* const restrict p) noexcept { #ifdef ZT_NO_UNALIGNED_ACCESS - return _load_be_bysize::l(reinterpret_cast(p)); + return _load_be_bysize::l(reinterpret_cast(p)); #else - return ntoh(*reinterpret_cast(p)); + return ntoh(*reinterpret_cast(p)); #endif } @@ -554,13 +544,12 @@ static ZT_INLINE I loadBigEndian(const void *const restrict p) noexcept * @param p Byte stream to write (must be at least sizeof(I)) * #param i Integer to write */ -template< typename I > -static ZT_INLINE void storeBigEndian(void *const restrict p, I i) noexcept +template static ZT_INLINE void storeBigEndian(void* const restrict p, I i) noexcept { #ifdef ZT_NO_UNALIGNED_ACCESS - storeMachineEndian(p,hton(i)); + storeMachineEndian(p, hton(i)); #else - *reinterpret_cast(p) = hton(i); + *reinterpret_cast(p) = hton(i); #endif } @@ -571,13 +560,12 @@ static ZT_INLINE void storeBigEndian(void *const restrict p, I i) noexcept * @param p Byte stream, must be at least sizeof(I) in size * @return Decoded integer */ -template< typename I > -static ZT_INLINE I loadLittleEndian(const void *const restrict p) noexcept +template static ZT_INLINE I loadLittleEndian(const void* const restrict p) noexcept { #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) - return _load_le_bysize::l(reinterpret_cast(p)); + return _load_le_bysize::l(reinterpret_cast(p)); #else - return *reinterpret_cast(p); + return *reinterpret_cast(p); #endif } @@ -588,16 +576,15 @@ static ZT_INLINE I loadLittleEndian(const void *const restrict p) noexcept * @param p Byte stream to write (must be at least sizeof(I)) * #param i Integer to write */ -template< typename I > -static ZT_INLINE void storeLittleEndian(void *const restrict p, const I i) noexcept +template static ZT_INLINE void storeLittleEndian(void* const restrict p, const I i) noexcept { #if __BYTE_ORDER == __BIG_ENDIAN - storeMachineEndian(p,_swap_bytes_bysize::s(i)); + storeMachineEndian(p, _swap_bytes_bysize::s(i)); #else #ifdef ZT_NO_UNALIGNED_ACCESS - storeMachineEndian(p,i); + storeMachineEndian(p, i); #else - *reinterpret_cast(p) = i; + *reinterpret_cast(p) = i; #endif #endif } @@ -609,14 +596,13 @@ static ZT_INLINE void storeLittleEndian(void *const restrict p, const I i) noexc * @param dest Destination memory * @param src Source memory */ -template< unsigned long L > -static ZT_INLINE void copy(void *dest, const void *src) noexcept +template static ZT_INLINE void copy(void* dest, const void* src) noexcept { #if defined(ZT_ARCH_X64) && defined(__GNUC__) - uintptr_t l = L; - __asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory"); + uintptr_t l = L; + __asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory"); #else - memcpy(dest, src, L); + memcpy(dest, src, L); #endif } @@ -627,12 +613,12 @@ static ZT_INLINE void copy(void *dest, const void *src) noexcept * @param src Source memory * @param len Bytes to copy */ -static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexcept +static ZT_INLINE void copy(void* dest, const void* src, unsigned long len) noexcept { #if defined(ZT_ARCH_X64) && defined(__GNUC__) - __asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory"); + __asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory"); #else - memcpy(dest, src, len); + memcpy(dest, src, len); #endif } @@ -642,14 +628,13 @@ static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexc * @tparam L Size in bytes * @param dest Memory to zero */ -template< unsigned long L > -static ZT_INLINE void zero(void *dest) noexcept +template static ZT_INLINE void zero(void* dest) noexcept { #if defined(ZT_ARCH_X64) && defined(__GNUC__) - uintptr_t l = L; - __asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory"); + uintptr_t l = L; + __asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory"); #else - memset(dest, 0, L); + memset(dest, 0, L); #endif } @@ -659,12 +644,12 @@ static ZT_INLINE void zero(void *dest) noexcept * @param dest Memory to zero * @param len Size in bytes */ -static ZT_INLINE void zero(void *dest, unsigned long len) noexcept +static ZT_INLINE void zero(void* dest, unsigned long len) noexcept { #if defined(ZT_ARCH_X64) && defined(__GNUC__) - __asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory"); + __asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory"); #else - memset(dest, 0, len); + memset(dest, 0, len); #endif } @@ -677,7 +662,7 @@ static ZT_INLINE void zero(void *dest, unsigned long len) noexcept * @param len Length of data * @return FNV1a checksum */ -uint32_t fnv1a32(const void *restrict data, unsigned int len) noexcept; +uint32_t fnv1a32(const void* restrict data, unsigned int len) noexcept; /** * Mix bits in a 64-bit integer (non-cryptographic, for hash tables) @@ -689,12 +674,12 @@ uint32_t fnv1a32(const void *restrict data, unsigned int len) noexcept; */ static ZT_INLINE uint64_t hash64(uint64_t x) noexcept { - x ^= x >> 30U; - x *= 0xbf58476d1ce4e5b9ULL; - x ^= x >> 27U; - x *= 0x94d049bb133111ebULL; - x ^= x >> 31U; - return x; + x ^= x >> 30U; + x *= 0xbf58476d1ce4e5b9ULL; + x ^= x >> 27U; + x *= 0x94d049bb133111ebULL; + x ^= x >> 31U; + return x; } /** @@ -707,16 +692,16 @@ static ZT_INLINE uint64_t hash64(uint64_t x) noexcept */ static ZT_INLINE uint32_t hash32(uint32_t x) noexcept { - x ^= x >> 16U; - x *= 0x7feb352dU; - x ^= x >> 15U; - x *= 0x846ca68bU; - x ^= x >> 16U; - return x; + x ^= x >> 16U; + x *= 0x7feb352dU; + x ^= x >> 15U; + x *= 0x846ca68bU; + x ^= x >> 16U; + return x; } -} // namespace Utils +} // namespace Utils -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/VL1.cpp b/core/VL1.cpp index 09aa462cf..163a0667a 100644 --- a/core/VL1.cpp +++ b/core/VL1.cpp @@ -12,632 +12,888 @@ /****/ #include "VL1.hpp" -#include "Context.hpp" -#include "Topology.hpp" -#include "VL2.hpp" + #include "AES.hpp" -#include "Salsa20.hpp" +#include "Context.hpp" +#include "Expect.hpp" +#include "Identity.hpp" #include "LZ4.hpp" +#include "Path.hpp" +#include "Peer.hpp" #include "Poly1305.hpp" #include "SHA512.hpp" -#include "Identity.hpp" +#include "Salsa20.hpp" #include "SelfAwareness.hpp" -#include "Peer.hpp" -#include "Path.hpp" -#include "Expect.hpp" +#include "Topology.hpp" +#include "VL2.hpp" namespace ZeroTier { namespace { -ZT_INLINE const Identity &identityFromPeerPtr(const SharedPtr< Peer > &p) -{ return (p) ? p->identity() : Identity::NIL; } - -struct p_SalsaPolyCopyFunction +ZT_INLINE const Identity& identityFromPeerPtr(const SharedPtr& p) { - Salsa20 s20; - Poly1305 poly1305; - unsigned int hdrRemaining; + return (p) ? p->identity() : Identity::NIL; +} - ZT_INLINE p_SalsaPolyCopyFunction(const void *salsaKey, const void *salsaIv) : - s20(salsaKey, salsaIv), - poly1305(), - hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START) - { - uint8_t macKey[ZT_POLY1305_KEY_SIZE]; - s20.crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); - poly1305.init(macKey); - } +struct p_SalsaPolyCopyFunction { + Salsa20 s20; + Poly1305 poly1305; + unsigned int hdrRemaining; - ZT_INLINE void operator()(void *dest, const void *src, unsigned int len) noexcept - { - if (hdrRemaining != 0) { - unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len; - Utils::copy(dest, src, hdrBytes); - hdrRemaining -= hdrBytes; - dest = reinterpret_cast(dest) + hdrBytes; - src = reinterpret_cast(src) + hdrBytes; - len -= hdrBytes; - } - poly1305.update(src, len); - s20.crypt12(src, dest, len); - } + ZT_INLINE p_SalsaPolyCopyFunction(const void* salsaKey, const void* salsaIv) + : s20(salsaKey, salsaIv) + , poly1305() + , hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START) + { + uint8_t macKey[ZT_POLY1305_KEY_SIZE]; + s20.crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); + poly1305.init(macKey); + } + + ZT_INLINE void operator()(void* dest, const void* src, unsigned int len) noexcept + { + if (hdrRemaining != 0) { + unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len; + Utils::copy(dest, src, hdrBytes); + hdrRemaining -= hdrBytes; + dest = reinterpret_cast(dest) + hdrBytes; + src = reinterpret_cast(src) + hdrBytes; + len -= hdrBytes; + } + poly1305.update(src, len); + s20.crypt12(src, dest, len); + } }; -struct p_PolyCopyFunction -{ - Poly1305 poly1305; - unsigned int hdrRemaining; +struct p_PolyCopyFunction { + Poly1305 poly1305; + unsigned int hdrRemaining; - ZT_INLINE p_PolyCopyFunction(const void *salsaKey, const void *salsaIv) : - poly1305(), - hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START) - { - uint8_t macKey[ZT_POLY1305_KEY_SIZE]; - Salsa20(salsaKey, salsaIv).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); - poly1305.init(macKey); - } + ZT_INLINE p_PolyCopyFunction(const void* salsaKey, const void* salsaIv) + : poly1305() + , hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START) + { + uint8_t macKey[ZT_POLY1305_KEY_SIZE]; + Salsa20(salsaKey, salsaIv).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); + poly1305.init(macKey); + } - ZT_INLINE void operator()(void *dest, const void *src, unsigned int len) noexcept - { - if (hdrRemaining != 0) { - unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len; - Utils::copy(dest, src, hdrBytes); - hdrRemaining -= hdrBytes; - dest = reinterpret_cast(dest) + hdrBytes; - src = reinterpret_cast(src) + hdrBytes; - len -= hdrBytes; - } - poly1305.update(src, len); - Utils::copy(dest, src, len); - } + ZT_INLINE void operator()(void* dest, const void* src, unsigned int len) noexcept + { + if (hdrRemaining != 0) { + unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len; + Utils::copy(dest, src, hdrBytes); + hdrRemaining -= hdrBytes; + dest = reinterpret_cast(dest) + hdrBytes; + src = reinterpret_cast(src) + hdrBytes; + len -= hdrBytes; + } + poly1305.update(src, len); + Utils::copy(dest, src, len); + } }; -} // anonymous namespace +} // anonymous namespace -VL1::VL1(const Context &ctx) : - m_ctx(ctx) -{} - -void VL1::onRemotePacket(CallContext &cc, const int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, const unsigned int len) noexcept -{ - const SharedPtr< Path > path(m_ctx.topology->path(localSocket, fromAddr)); - - ZT_SPEW("%u bytes from %s (local socket %lld)", len, fromAddr.toString().c_str(), localSocket); - path->received(cc, len); - - // NOTE: likely/unlikely are used here to highlight the most common code path - // for valid data packets. This may allow the compiler to generate very slightly - // faster code for that path. - - try { - if (unlikely(len < ZT_PROTO_MIN_FRAGMENT_LENGTH)) - return; - - static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); - const uint64_t packetId = Utils::loadMachineEndian< uint64_t >(data->unsafeData + ZT_PROTO_PACKET_ID_INDEX); - - static_assert((ZT_PROTO_PACKET_DESTINATION_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); - const Address destination(data->unsafeData + ZT_PROTO_PACKET_DESTINATION_INDEX); - if (destination != m_ctx.identity.address()) { - m_relay(cc, path, destination, data, len); - return; - } - - // ---------------------------------------------------------------------------------------------------------------- - // If we made it this far, the packet is at least MIN_FRAGMENT_LENGTH and is addressed to this node's ZT address - // ---------------------------------------------------------------------------------------------------------------- - - Buf::PacketVector pktv; - - static_assert(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX <= ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); - if (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX] == ZT_PROTO_PACKET_FRAGMENT_INDICATOR) { - // This looks like a fragment (excluding the head) of a larger packet. - static_assert(ZT_PROTO_PACKET_FRAGMENT_COUNTS < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); - const unsigned int totalFragments = (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] >> 4U) & 0x0fU; - const unsigned int fragmentNo = data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] & 0x0fU; - switch (m_inputPacketAssembler.assemble( - packetId, - pktv, - data, - ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT, - len - ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT, - fragmentNo, - totalFragments, - cc.ticks, - path)) { - case Defragmenter< ZT_MAX_PACKET_FRAGMENTS >::COMPLETE: - break; - default: - //case Defragmenter::OK: - //case Defragmenter::ERR_DUPLICATE_FRAGMENT: - //case Defragmenter::ERR_INVALID_FRAGMENT: - //case Defragmenter::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: - //case Defragmenter::ERR_OUT_OF_MEMORY: - return; - } - } else { - if (unlikely(len < ZT_PROTO_MIN_PACKET_LENGTH)) - return; - static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - if ((data->unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { - // This is the head of a series of fragments that we may or may not already have. - switch (m_inputPacketAssembler.assemble( - packetId, - pktv, - data, - 0, // fragment index is 0 since this is the head - len, - 0, // always the zero'eth fragment - 0, // this is specified in fragments, not in the head - cc.ticks, - path)) { - case Defragmenter< ZT_MAX_PACKET_FRAGMENTS >::COMPLETE: - break; - default: - //case Defragmenter::OK: - //case Defragmenter::ERR_DUPLICATE_FRAGMENT: - //case Defragmenter::ERR_INVALID_FRAGMENT: - //case Defragmenter::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: - //case Defragmenter::ERR_OUT_OF_MEMORY: - return; - } - } else { - // This is a single whole packet with no fragments. - Buf::Slice s = pktv.push(); - s.b.swap(data); - s.s = 0; - s.e = len; - } - } - - // ---------------------------------------------------------------------------------------------------------------- - // If we made it this far without returning, a packet is fully assembled and ready to process. - // ---------------------------------------------------------------------------------------------------------------- - - const uint8_t *const hdr = pktv[0].b->unsafeData + pktv[0].s; - static_assert((ZT_PROTO_PACKET_SOURCE_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - const Address source(hdr + ZT_PROTO_PACKET_SOURCE_INDEX); - static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - const uint8_t hops = hdr[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK; - const uint8_t cipher = (hdr[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 3U; - - SharedPtr< Buf > pkt(new Buf()); - int pktSize = 0; - - static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - if (unlikely(((cipher == ZT_PROTO_CIPHER_POLY1305_NONE) || (cipher == ZT_PROTO_CIPHER_NONE)) && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO))) { - // Handle unencrypted HELLO packets. - pktSize = pktv.mergeCopy(*pkt); - if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { - ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize); - return; - } - const SharedPtr< Peer > peer(m_HELLO(cc, path, *pkt, pktSize)); - if (likely(peer)) - peer->received(m_ctx, cc, path, hops, packetId, pktSize - ZT_PROTO_PACKET_PAYLOAD_START, Protocol::VERB_HELLO, Protocol::VERB_NOP); - return; - } - - // This remains zero if authentication fails. Otherwise it gets set to a bit mask - // indicating authentication and other security flags like encryption and forward - // secrecy status. - unsigned int auth = 0; - - SharedPtr< Peer > peer(m_ctx.topology->peer(cc, source)); - if (likely(peer)) { - switch (cipher) { - - case ZT_PROTO_CIPHER_POLY1305_NONE: { - uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; - Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize()); - p_PolyCopyFunction s20cf(perPacketKey, &packetId); - - pktSize = pktv.mergeMap< p_PolyCopyFunction & >(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf); - if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { - ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize); - return; - } - - uint64_t mac[2]; - s20cf.poly1305.finish(mac); - static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - if (unlikely(Utils::loadMachineEndian< uint64_t >(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) { - ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (none/poly1305)", packetId, source.toString().c_str(), fromAddr.toString().c_str()); - m_ctx.t->incomingPacketDropped(cc, 0xcc89c812, packetId, 0, peer->identity(), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return; - } - - auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED; - } - break; - - case ZT_PROTO_CIPHER_POLY1305_SALSA2012: { - uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; - Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize()); - p_SalsaPolyCopyFunction s20cf(perPacketKey, &packetId); - - pktSize = pktv.mergeMap< p_SalsaPolyCopyFunction & >(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf); - if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { - ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize); - return; - } - - uint64_t mac[2]; - s20cf.poly1305.finish(mac); - static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - if (unlikely(Utils::loadMachineEndian< uint64_t >(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) { - ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (salsa/poly1305)", packetId, source.toString().c_str(), fromAddr.toString().c_str()); - m_ctx.t->incomingPacketDropped(cc, 0xcc89c812, packetId, 0, peer->identity(), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return; - } - - auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED | ZT_VL1_AUTH_RESULT_FLAG_ENCRYPTED; - } - break; - - case ZT_PROTO_CIPHER_NONE: { - // TODO - } - break; - - case ZT_PROTO_CIPHER_AES_GMAC_SIV: { - // TODO - } - break; - - default: - m_ctx.t->incomingPacketDropped(cc, 0x5b001099, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return; - } - } - - if (likely(auth != 0)) { - // If authentication was successful go on and process the packet. - - if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { - ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size %d is smaller than minimum packet length", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize); - return; - } - - // TODO: should take instance ID into account here once that is fully implemented. - if (unlikely(peer->deduplicateIncomingPacket(packetId))) { - ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!", packetId, source.toString().c_str(), fromAddr.toString().c_str()); - return; - } - - static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); - const uint8_t verbFlags = pkt->unsafeData[ZT_PROTO_PACKET_VERB_INDEX]; - const Protocol::Verb verb = (Protocol::Verb)(verbFlags & ZT_PROTO_VERB_MASK); - - // Decompress packet payload if compressed. For additional safety decompression is - // only performed on packets whose MACs have already been validated. (Only HELLO is - // sent without this, and HELLO doesn't benefit from compression.) - if (((verbFlags & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) && (pktSize > ZT_PROTO_PACKET_PAYLOAD_START)) { - SharedPtr< Buf > dec(new Buf()); - Utils::copy< ZT_PROTO_PACKET_PAYLOAD_START >(dec->unsafeData, pkt->unsafeData); - const int uncompressedLen = LZ4_decompress_safe( - reinterpret_cast(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START), - reinterpret_cast(dec->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START), - pktSize - ZT_PROTO_PACKET_PAYLOAD_START, - ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START); - if (likely((uncompressedLen >= 0) && (uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) { - pkt.swap(dec); - ZT_SPEW("decompressed packet: %d -> %d", pktSize, ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen); - pktSize = ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen; - } else { - m_ctx.t->incomingPacketDropped(cc, 0xee9e4392, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, verb, ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA); - return; - } - } - - ZT_SPEW("%s from %s(%s) (%d bytes)", Protocol::verbName(verb), source.toString().c_str(), fromAddr.toString().c_str(), pktSize); - - // NOTE: HELLO is normally sent in the clear (in terms of our usual AEAD modes) and is handled - // above. We will try to process it here, but if so it'll still get re-authenticated via HELLO's - // own internal authentication logic as usual. It would be abnormal to make it here with HELLO - // but not invalid. - - Protocol::Verb inReVerb = Protocol::VERB_NOP; - bool ok = true; - switch (verb) { - case Protocol::VERB_NOP: - break; - case Protocol::VERB_HELLO: - ok = (bool)(m_HELLO(cc, path, *pkt, pktSize)); - break; - case Protocol::VERB_ERROR: - ok = m_ERROR(cc, packetId, auth, path, peer, *pkt, pktSize, inReVerb); - break; - case Protocol::VERB_OK: - ok = m_OK(cc, packetId, auth, path, peer, *pkt, pktSize, inReVerb); - break; - case Protocol::VERB_WHOIS: - ok = m_WHOIS(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_RENDEZVOUS: - ok = m_RENDEZVOUS(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_FRAME: - ok = m_ctx.vl2->m_FRAME(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_EXT_FRAME: - ok = m_ctx.vl2->m_EXT_FRAME(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_ECHO: - ok = m_ECHO(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_MULTICAST_LIKE: - ok = m_ctx.vl2->m_MULTICAST_LIKE(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_NETWORK_CREDENTIALS: - ok = m_ctx.vl2->m_NETWORK_CREDENTIALS(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_NETWORK_CONFIG_REQUEST: - ok = m_ctx.vl2->m_NETWORK_CONFIG_REQUEST(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_NETWORK_CONFIG: - ok = m_ctx.vl2->m_NETWORK_CONFIG(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_MULTICAST_GATHER: - ok = m_ctx.vl2->m_MULTICAST_GATHER(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_MULTICAST_FRAME_deprecated: - ok = m_ctx.vl2->m_MULTICAST_FRAME_deprecated(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_PUSH_DIRECT_PATHS: - ok = m_PUSH_DIRECT_PATHS(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_USER_MESSAGE: - ok = m_USER_MESSAGE(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_MULTICAST: - ok = m_ctx.vl2->m_MULTICAST(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - case Protocol::VERB_ENCAP: - ok = m_ENCAP(cc, packetId, auth, path, peer, *pkt, pktSize); - break; - - default: - m_ctx.t->incomingPacketDropped(cc, 0xeeeeeff0, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, verb, ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB); - break; - } - if (likely(ok)) - peer->received(m_ctx, cc, path, hops, packetId, pktSize - ZT_PROTO_PACKET_PAYLOAD_START, verb, inReVerb); - } else { - // If decryption and authentication were not successful, try to look up identities. - // This is rate limited by virtue of the retry rate limit timer. - if (pktSize <= 0) - pktSize = pktv.mergeCopy(*pkt); - if (likely(pktSize >= ZT_PROTO_MIN_PACKET_LENGTH)) { - ZT_SPEW("authentication failed or no peers match, queueing WHOIS for %s", source.toString().c_str()); - bool sendPending; - { - Mutex::Lock wl(m_whoisQueue_l); - p_WhoisQueueItem &wq = m_whoisQueue[source]; - const unsigned int wpidx = wq.waitingPacketCount++ % ZT_VL1_MAX_WHOIS_WAITING_PACKETS; - wq.waitingPacketSize[wpidx] = (unsigned int)pktSize; - wq.waitingPacket[wpidx] = pkt; - sendPending = (cc.ticks - wq.lastRetry) >= ZT_WHOIS_RETRY_DELAY; - } - if (sendPending) - m_sendPendingWhois(cc); - } - } - } catch (...) { - m_ctx.t->unexpectedError(cc, 0xea1b6dea, "unexpected exception in onRemotePacket() parsing packet from %s", path->address().toString().c_str()); - } -} - -void VL1::m_relay(CallContext &cc, const SharedPtr< Path > &path, Address destination, SharedPtr< Buf > &pkt, int pktSize) +VL1::VL1(const Context& ctx) : m_ctx(ctx) { } -void VL1::m_sendPendingWhois(CallContext &cc) +void VL1::onRemotePacket( + CallContext& cc, + const int64_t localSocket, + const InetAddress& fromAddr, + SharedPtr& data, + const unsigned int len) noexcept { - const SharedPtr< Peer > root(m_ctx.topology->root()); - if (unlikely(!root)) - return; - const SharedPtr< Path > rootPath(root->path(cc)); - if (unlikely(!rootPath)) - return; + const SharedPtr path(m_ctx.topology->path(localSocket, fromAddr)); - Vector< Address > toSend; - { - Mutex::Lock wl(m_whoisQueue_l); - for (Map< Address, p_WhoisQueueItem >::iterator wi(m_whoisQueue.begin()); wi != m_whoisQueue.end(); ++wi) { - if ((cc.ticks - wi->second.lastRetry) >= ZT_WHOIS_RETRY_DELAY) { - wi->second.lastRetry = cc.ticks; - ++wi->second.retries; - toSend.push_back(wi->first); - } - } - } + ZT_SPEW("%u bytes from %s (local socket %lld)", len, fromAddr.toString().c_str(), localSocket); + path->received(cc, len); - if (!toSend.empty()) { - SymmetricKey &key = root->key(); - uint8_t outp[ZT_DEFAULT_UDP_MTU - ZT_PROTO_MIN_PACKET_LENGTH]; - Vector< Address >::iterator a(toSend.begin()); - while (a != toSend.end()) { - const uint64_t packetId = key.nextMessage(m_ctx.identity.address(), root->address()); - int p = Protocol::newPacket(outp, packetId, root->address(), m_ctx.identity.address(), Protocol::VERB_WHOIS); - while ((a != toSend.end()) && (p < (sizeof(outp) - ZT_ADDRESS_LENGTH))) { - a->copyTo(outp + p); - ++a; - p += ZT_ADDRESS_LENGTH; - } - m_ctx.expect->sending(Protocol::armor(outp, p, key, root->cipher()), cc.ticks); - root->send(m_ctx, cc, outp, p, rootPath); - } - } + // NOTE: likely/unlikely are used here to highlight the most common code path + // for valid data packets. This may allow the compiler to generate very slightly + // faster code for that path. + + try { + if (unlikely(len < ZT_PROTO_MIN_FRAGMENT_LENGTH)) + return; + + static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); + const uint64_t packetId = Utils::loadMachineEndian(data->unsafeData + ZT_PROTO_PACKET_ID_INDEX); + + static_assert( + (ZT_PROTO_PACKET_DESTINATION_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_FRAGMENT_LENGTH, + "overflow"); + const Address destination(data->unsafeData + ZT_PROTO_PACKET_DESTINATION_INDEX); + if (destination != m_ctx.identity.address()) { + m_relay(cc, path, destination, data, len); + return; + } + + // ---------------------------------------------------------------------------------------------------------------- + // If we made it this far, the packet is at least MIN_FRAGMENT_LENGTH and is addressed to this node's ZT address + // ---------------------------------------------------------------------------------------------------------------- + + Buf::PacketVector pktv; + + static_assert(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX <= ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); + if (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX] == ZT_PROTO_PACKET_FRAGMENT_INDICATOR) { + // This looks like a fragment (excluding the head) of a larger packet. + static_assert(ZT_PROTO_PACKET_FRAGMENT_COUNTS < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow"); + const unsigned int totalFragments = (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] >> 4U) & 0x0fU; + const unsigned int fragmentNo = data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] & 0x0fU; + switch (m_inputPacketAssembler.assemble( + packetId, + pktv, + data, + ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT, + len - ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT, + fragmentNo, + totalFragments, + cc.ticks, + path)) { + case Defragmenter::COMPLETE: + break; + default: + // case Defragmenter::OK: + // case Defragmenter::ERR_DUPLICATE_FRAGMENT: + // case Defragmenter::ERR_INVALID_FRAGMENT: + // case Defragmenter::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: + // case Defragmenter::ERR_OUT_OF_MEMORY: + return; + } + } + else { + if (unlikely(len < ZT_PROTO_MIN_PACKET_LENGTH)) + return; + static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + if ((data->unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { + // This is the head of a series of fragments that we may or may not already have. + switch (m_inputPacketAssembler.assemble( + packetId, + pktv, + data, + 0, // fragment index is 0 since this is the head + len, + 0, // always the zero'eth fragment + 0, // this is specified in fragments, not in the head + cc.ticks, + path)) { + case Defragmenter::COMPLETE: + break; + default: + // case Defragmenter::OK: + // case Defragmenter::ERR_DUPLICATE_FRAGMENT: + // case Defragmenter::ERR_INVALID_FRAGMENT: + // case Defragmenter::ERR_TOO_MANY_FRAGMENTS_FOR_PATH: + // case Defragmenter::ERR_OUT_OF_MEMORY: + return; + } + } + else { + // This is a single whole packet with no fragments. + Buf::Slice s = pktv.push(); + s.b.swap(data); + s.s = 0; + s.e = len; + } + } + + // ---------------------------------------------------------------------------------------------------------------- + // If we made it this far without returning, a packet is fully assembled and ready to process. + // ---------------------------------------------------------------------------------------------------------------- + + const uint8_t* const hdr = pktv[0].b->unsafeData + pktv[0].s; + static_assert((ZT_PROTO_PACKET_SOURCE_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + const Address source(hdr + ZT_PROTO_PACKET_SOURCE_INDEX); + static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + const uint8_t hops = hdr[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK; + const uint8_t cipher = (hdr[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 3U; + + SharedPtr pkt(new Buf()); + int pktSize = 0; + + static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + if (unlikely( + ((cipher == ZT_PROTO_CIPHER_POLY1305_NONE) || (cipher == ZT_PROTO_CIPHER_NONE)) + && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO))) { + // Handle unencrypted HELLO packets. + pktSize = pktv.mergeCopy(*pkt); + if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): assembled packet size: %d", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str(), + pktSize); + return; + } + const SharedPtr peer(m_HELLO(cc, path, *pkt, pktSize)); + if (likely(peer)) + peer->received( + m_ctx, + cc, + path, + hops, + packetId, + pktSize - ZT_PROTO_PACKET_PAYLOAD_START, + Protocol::VERB_HELLO, + Protocol::VERB_NOP); + return; + } + + // This remains zero if authentication fails. Otherwise it gets set to a bit mask + // indicating authentication and other security flags like encryption and forward + // secrecy status. + unsigned int auth = 0; + + SharedPtr peer(m_ctx.topology->peer(cc, source)); + if (likely(peer)) { + switch (cipher) { + case ZT_PROTO_CIPHER_POLY1305_NONE: { + uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; + Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize()); + p_PolyCopyFunction s20cf(perPacketKey, &packetId); + + pktSize = pktv.mergeMap(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf); + if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): assembled packet size: %d", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str(), + pktSize); + return; + } + + uint64_t mac[2]; + s20cf.poly1305.finish(mac); + static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + if (unlikely(Utils::loadMachineEndian(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): packet MAC failed (none/poly1305)", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str()); + m_ctx.t->incomingPacketDropped( + cc, + 0xcc89c812, + packetId, + 0, + peer->identity(), + path->address(), + hops, + Protocol::VERB_NOP, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return; + } + + auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED; + } break; + + case ZT_PROTO_CIPHER_POLY1305_SALSA2012: { + uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; + Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize()); + p_SalsaPolyCopyFunction s20cf(perPacketKey, &packetId); + + pktSize = + pktv.mergeMap(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf); + if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): assembled packet size: %d", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str(), + pktSize); + return; + } + + uint64_t mac[2]; + s20cf.poly1305.finish(mac); + static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + if (unlikely(Utils::loadMachineEndian(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): packet MAC failed (salsa/poly1305)", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str()); + m_ctx.t->incomingPacketDropped( + cc, + 0xcc89c812, + packetId, + 0, + peer->identity(), + path->address(), + hops, + Protocol::VERB_NOP, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return; + } + + auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED | ZT_VL1_AUTH_RESULT_FLAG_ENCRYPTED; + } break; + + case ZT_PROTO_CIPHER_NONE: { + // TODO + } break; + + case ZT_PROTO_CIPHER_AES_GMAC_SIV: { + // TODO + } break; + + default: + m_ctx.t->incomingPacketDropped( + cc, + 0x5b001099, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_NOP, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return; + } + } + + if (likely(auth != 0)) { + // If authentication was successful go on and process the packet. + + if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): assembled packet size %d is smaller than minimum packet " + "length", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str(), + pktSize); + return; + } + + // TODO: should take instance ID into account here once that is fully implemented. + if (unlikely(peer->deduplicateIncomingPacket(packetId))) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): duplicate!", + packetId, + source.toString().c_str(), + fromAddr.toString().c_str()); + return; + } + + static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow"); + const uint8_t verbFlags = pkt->unsafeData[ZT_PROTO_PACKET_VERB_INDEX]; + const Protocol::Verb verb = (Protocol::Verb)(verbFlags & ZT_PROTO_VERB_MASK); + + // Decompress packet payload if compressed. For additional safety decompression is + // only performed on packets whose MACs have already been validated. (Only HELLO is + // sent without this, and HELLO doesn't benefit from compression.) + if (((verbFlags & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) && (pktSize > ZT_PROTO_PACKET_PAYLOAD_START)) { + SharedPtr dec(new Buf()); + Utils::copy(dec->unsafeData, pkt->unsafeData); + const int uncompressedLen = LZ4_decompress_safe( + reinterpret_cast(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START), + reinterpret_cast(dec->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START), + pktSize - ZT_PROTO_PACKET_PAYLOAD_START, + ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START); + if (likely( + (uncompressedLen >= 0) + && (uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) { + pkt.swap(dec); + ZT_SPEW("decompressed packet: %d -> %d", pktSize, ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen); + pktSize = ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen; + } + else { + m_ctx.t->incomingPacketDropped( + cc, + 0xee9e4392, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + verb, + ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA); + return; + } + } + + ZT_SPEW( + "%s from %s(%s) (%d bytes)", + Protocol::verbName(verb), + source.toString().c_str(), + fromAddr.toString().c_str(), + pktSize); + + // NOTE: HELLO is normally sent in the clear (in terms of our usual AEAD modes) and is handled + // above. We will try to process it here, but if so it'll still get re-authenticated via HELLO's + // own internal authentication logic as usual. It would be abnormal to make it here with HELLO + // but not invalid. + + Protocol::Verb inReVerb = Protocol::VERB_NOP; + bool ok = true; + switch (verb) { + case Protocol::VERB_NOP: + break; + case Protocol::VERB_HELLO: + ok = (bool)(m_HELLO(cc, path, *pkt, pktSize)); + break; + case Protocol::VERB_ERROR: + ok = m_ERROR(cc, packetId, auth, path, peer, *pkt, pktSize, inReVerb); + break; + case Protocol::VERB_OK: + ok = m_OK(cc, packetId, auth, path, peer, *pkt, pktSize, inReVerb); + break; + case Protocol::VERB_WHOIS: + ok = m_WHOIS(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_RENDEZVOUS: + ok = m_RENDEZVOUS(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_FRAME: + ok = m_ctx.vl2->m_FRAME(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_EXT_FRAME: + ok = m_ctx.vl2->m_EXT_FRAME(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_ECHO: + ok = m_ECHO(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_MULTICAST_LIKE: + ok = m_ctx.vl2->m_MULTICAST_LIKE(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_NETWORK_CREDENTIALS: + ok = m_ctx.vl2->m_NETWORK_CREDENTIALS(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_NETWORK_CONFIG_REQUEST: + ok = m_ctx.vl2->m_NETWORK_CONFIG_REQUEST(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_NETWORK_CONFIG: + ok = m_ctx.vl2->m_NETWORK_CONFIG(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_MULTICAST_GATHER: + ok = m_ctx.vl2->m_MULTICAST_GATHER(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_MULTICAST_FRAME_deprecated: + ok = m_ctx.vl2->m_MULTICAST_FRAME_deprecated(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_PUSH_DIRECT_PATHS: + ok = m_PUSH_DIRECT_PATHS(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_USER_MESSAGE: + ok = m_USER_MESSAGE(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_MULTICAST: + ok = m_ctx.vl2->m_MULTICAST(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + case Protocol::VERB_ENCAP: + ok = m_ENCAP(cc, packetId, auth, path, peer, *pkt, pktSize); + break; + + default: + m_ctx.t->incomingPacketDropped( + cc, + 0xeeeeeff0, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + verb, + ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB); + break; + } + if (likely(ok)) + peer->received( + m_ctx, + cc, + path, + hops, + packetId, + pktSize - ZT_PROTO_PACKET_PAYLOAD_START, + verb, + inReVerb); + } + else { + // If decryption and authentication were not successful, try to look up identities. + // This is rate limited by virtue of the retry rate limit timer. + if (pktSize <= 0) + pktSize = pktv.mergeCopy(*pkt); + if (likely(pktSize >= ZT_PROTO_MIN_PACKET_LENGTH)) { + ZT_SPEW("authentication failed or no peers match, queueing WHOIS for %s", source.toString().c_str()); + bool sendPending; + { + Mutex::Lock wl(m_whoisQueue_l); + p_WhoisQueueItem& wq = m_whoisQueue[source]; + const unsigned int wpidx = wq.waitingPacketCount++ % ZT_VL1_MAX_WHOIS_WAITING_PACKETS; + wq.waitingPacketSize[wpidx] = (unsigned int)pktSize; + wq.waitingPacket[wpidx] = pkt; + sendPending = (cc.ticks - wq.lastRetry) >= ZT_WHOIS_RETRY_DELAY; + } + if (sendPending) + m_sendPendingWhois(cc); + } + } + } + catch (...) { + m_ctx.t->unexpectedError( + cc, + 0xea1b6dea, + "unexpected exception in onRemotePacket() parsing packet from %s", + path->address().toString().c_str()); + } } -SharedPtr< Peer > VL1::m_HELLO(CallContext &cc, const SharedPtr< Path > &path, Buf &pkt, int packetSize) +void VL1::m_relay(CallContext& cc, const SharedPtr& path, Address destination, SharedPtr& pkt, int pktSize) { - const uint64_t packetId = Utils::loadMachineEndian< uint64_t >(pkt.unsafeData + ZT_PROTO_PACKET_ID_INDEX); - const uint64_t mac = Utils::loadMachineEndian< uint64_t >(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX); - const uint8_t hops = pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK; - - const uint8_t protoVersion = pkt.lI8< ZT_PROTO_PACKET_PAYLOAD_START >(); - if (unlikely(protoVersion < ZT_PROTO_VERSION_MIN)) { - m_ctx.t->incomingPacketDropped(cc, 0x907a9891, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD); - return SharedPtr< Peer >(); - } - const unsigned int versionMajor = pkt.lI8< ZT_PROTO_PACKET_PAYLOAD_START + 1 >(); - const unsigned int versionMinor = pkt.lI8< ZT_PROTO_PACKET_PAYLOAD_START + 2 >(); - const unsigned int versionRev = pkt.lI16< ZT_PROTO_PACKET_PAYLOAD_START + 3 >(); - const uint64_t timestamp = pkt.lI64< ZT_PROTO_PACKET_PAYLOAD_START + 5 >(); - - int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13; - - // Get identity and verify that it matches the sending address in the packet. - Identity id; - if (unlikely(pkt.rO(ii, id) < 0)) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9810, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return SharedPtr< Peer >(); - } - if (unlikely(id.address() != Address(pkt.unsafeData + ZT_PROTO_PACKET_SOURCE_INDEX))) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9010, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - - // Get the peer that matches this identity, or learn a new one if we don't know it. - SharedPtr< Peer > peer(m_ctx.topology->peer(cc, id.address(), true)); - if (peer) { - if (unlikely(peer->identity() != id)) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - if (unlikely(peer->deduplicateIncomingPacket(packetId))) { - ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!", packetId, id.address().toString().c_str(), path->address().toString().c_str()); - return SharedPtr< Peer >(); - } - } else { - if (unlikely(!id.locallyValidate())) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9892, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return SharedPtr< Peer >(); - } - peer.set(new Peer()); - if (unlikely(!peer->init(m_ctx, cc, id))) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9893, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED); - return SharedPtr< Peer >(); - } - peer = m_ctx.topology->add(cc, peer); - } - - // ------------------------------------------------------------------------------------------------------------------ - // If we made it this far, peer is non-NULL and the identity is valid and matches it. - // ------------------------------------------------------------------------------------------------------------------ - - if (protoVersion >= 11) { - // V2.x and newer use HMAC-SHA384 for HELLO, which offers a larger security margin - // to guard key exchange and connection setup than typical AEAD. The packet MAC - // field is ignored, and eventually it'll be undefined. - uint8_t hmac[ZT_HMACSHA384_LEN]; - if (unlikely(packetSize < ZT_HMACSHA384_LEN)) { - m_ctx.t->incomingPacketDropped(cc, 0xab9c9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - packetSize -= ZT_HMACSHA384_LEN; - pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] &= ~ZT_PROTO_FLAG_FIELD_HOPS_MASK; // mask hops to 0 - Utils::storeMachineEndian< uint64_t >(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, 0); // set MAC field to 0 - HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, packetSize, hmac); - if (unlikely(!Utils::secureEq(hmac, pkt.unsafeData + packetSize, ZT_HMACSHA384_LEN))) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - } else { - // Older versions use Poly1305 MAC (but no whole packet encryption) for HELLO. - if (likely(packetSize > ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)) { - uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; - Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, pkt, packetSize); - uint8_t macKey[ZT_POLY1305_KEY_SIZE]; - Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); - Poly1305 poly1305(macKey); - poly1305.update(pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START); - uint64_t polyMac[2]; - poly1305.finish(polyMac); - if (unlikely(mac != polyMac[0])) { - m_ctx.t->incomingPacketDropped(cc, 0x11bfff82, packetId, 0, id, path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - } else { - m_ctx.t->incomingPacketDropped(cc, 0x11bfff81, packetId, 0, id, path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); - return SharedPtr< Peer >(); - } - } - - // ------------------------------------------------------------------------------------------------------------------ - // This far means we passed MAC (Poly1305 or HMAC-SHA384 for newer peers) - // ------------------------------------------------------------------------------------------------------------------ - - InetAddress sentTo; - if (unlikely(pkt.rO(ii, sentTo) < 0)) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9811, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return SharedPtr< Peer >(); - } - - SymmetricKey &key = peer->key(); - - if (protoVersion >= 11) { - // V2.x and newer supports an encrypted section and has a new OK format. - ii += 4; // skip reserved field - if (likely((ii + 12) < packetSize)) { - AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher()); - const uint8_t *const ctrNonce = pkt.unsafeData + ii; - ii += 12; - ctr.init(ctrNonce, 0, pkt.unsafeData + ii); - ctr.crypt(pkt.unsafeData + ii, packetSize - ii); - ctr.finish(); - - ii += 2; // skip reserved field - const unsigned int dictSize = pkt.rI16(ii); - if (unlikely((ii + dictSize) > packetSize)) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9815, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return peer; - } - Dictionary md; - if (!md.decode(pkt.unsafeData + ii, dictSize)) { - m_ctx.t->incomingPacketDropped(cc, 0x707a9816, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); - return peer; - } - - if (!md.empty()) { - // TODO - } - } - } - - Protocol::newPacket(pkt, key.nextMessage(m_ctx.identity.address(), peer->address()), peer->address(), m_ctx.identity.address(), Protocol::VERB_OK); - ii = ZT_PROTO_PACKET_PAYLOAD_START; - pkt.wI8(ii, Protocol::VERB_HELLO); - pkt.wI64(ii, packetId); - pkt.wI64(ii, timestamp); - pkt.wI8(ii, ZT_PROTO_VERSION); - pkt.wI8(ii, ZEROTIER_VERSION_MAJOR); - pkt.wI8(ii, ZEROTIER_VERSION_MINOR); - pkt.wI16(ii, ZEROTIER_VERSION_REVISION); - pkt.wO(ii, path->address()); - pkt.wI16(ii, 0); // reserved, specifies no "moons" for older versions - - if (protoVersion >= 11) { - FCV< uint8_t, 1024 > okmd; - pkt.wI16(ii, (uint16_t)okmd.size()); - pkt.wB(ii, okmd.data(), okmd.size()); - - if (unlikely((ii + ZT_HMACSHA384_LEN) > ZT_BUF_MEM_SIZE)) // sanity check, should be impossible - return SharedPtr< Peer >(); - - HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, ii, pkt.unsafeData + ii); - ii += ZT_HMACSHA384_LEN; - } - - peer->setRemoteVersion(protoVersion, versionMajor, versionMinor, versionRev); - peer->send(m_ctx, cc, pkt.unsafeData, ii, path); - return peer; } -bool VL1::m_ERROR(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb) +void VL1::m_sendPendingWhois(CallContext& cc) +{ + const SharedPtr root(m_ctx.topology->root()); + if (unlikely(! root)) + return; + const SharedPtr rootPath(root->path(cc)); + if (unlikely(! rootPath)) + return; + + Vector
toSend; + { + Mutex::Lock wl(m_whoisQueue_l); + for (Map::iterator wi(m_whoisQueue.begin()); wi != m_whoisQueue.end(); ++wi) { + if ((cc.ticks - wi->second.lastRetry) >= ZT_WHOIS_RETRY_DELAY) { + wi->second.lastRetry = cc.ticks; + ++wi->second.retries; + toSend.push_back(wi->first); + } + } + } + + if (! toSend.empty()) { + SymmetricKey& key = root->key(); + uint8_t outp[ZT_DEFAULT_UDP_MTU - ZT_PROTO_MIN_PACKET_LENGTH]; + Vector
::iterator a(toSend.begin()); + while (a != toSend.end()) { + const uint64_t packetId = key.nextMessage(m_ctx.identity.address(), root->address()); + int p = + Protocol::newPacket(outp, packetId, root->address(), m_ctx.identity.address(), Protocol::VERB_WHOIS); + while ((a != toSend.end()) && (p < (sizeof(outp) - ZT_ADDRESS_LENGTH))) { + a->copyTo(outp + p); + ++a; + p += ZT_ADDRESS_LENGTH; + } + m_ctx.expect->sending(Protocol::armor(outp, p, key, root->cipher()), cc.ticks); + root->send(m_ctx, cc, outp, p, rootPath); + } + } +} + +SharedPtr VL1::m_HELLO(CallContext& cc, const SharedPtr& path, Buf& pkt, int packetSize) +{ + const uint64_t packetId = Utils::loadMachineEndian(pkt.unsafeData + ZT_PROTO_PACKET_ID_INDEX); + const uint64_t mac = Utils::loadMachineEndian(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX); + const uint8_t hops = pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK; + + const uint8_t protoVersion = pkt.lI8(); + if (unlikely(protoVersion < ZT_PROTO_VERSION_MIN)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x907a9891, + packetId, + 0, + Identity::NIL, + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD); + return SharedPtr(); + } + const unsigned int versionMajor = pkt.lI8(); + const unsigned int versionMinor = pkt.lI8(); + const unsigned int versionRev = pkt.lI16(); + const uint64_t timestamp = pkt.lI64(); + + int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13; + + // Get identity and verify that it matches the sending address in the packet. + Identity id; + if (unlikely(pkt.rO(ii, id) < 0)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9810, + packetId, + 0, + Identity::NIL, + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return SharedPtr(); + } + if (unlikely(id.address() != Address(pkt.unsafeData + ZT_PROTO_PACKET_SOURCE_INDEX))) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9010, + packetId, + 0, + Identity::NIL, + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + + // Get the peer that matches this identity, or learn a new one if we don't know it. + SharedPtr peer(m_ctx.topology->peer(cc, id.address(), true)); + if (peer) { + if (unlikely(peer->identity() != id)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9891, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + if (unlikely(peer->deduplicateIncomingPacket(packetId))) { + ZT_SPEW( + "discarding packet %.16llx from %s(%s): duplicate!", + packetId, + id.address().toString().c_str(), + path->address().toString().c_str()); + return SharedPtr(); + } + } + else { + if (unlikely(! id.locallyValidate())) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9892, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return SharedPtr(); + } + peer.set(new Peer()); + if (unlikely(! peer->init(m_ctx, cc, id))) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9893, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED); + return SharedPtr(); + } + peer = m_ctx.topology->add(cc, peer); + } + + // ------------------------------------------------------------------------------------------------------------------ + // If we made it this far, peer is non-NULL and the identity is valid and matches it. + // ------------------------------------------------------------------------------------------------------------------ + + if (protoVersion >= 11) { + // V2.x and newer use HMAC-SHA384 for HELLO, which offers a larger security margin + // to guard key exchange and connection setup than typical AEAD. The packet MAC + // field is ignored, and eventually it'll be undefined. + uint8_t hmac[ZT_HMACSHA384_LEN]; + if (unlikely(packetSize < ZT_HMACSHA384_LEN)) { + m_ctx.t->incomingPacketDropped( + cc, + 0xab9c9891, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + packetSize -= ZT_HMACSHA384_LEN; + pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] &= ~ZT_PROTO_FLAG_FIELD_HOPS_MASK; // mask hops to 0 + Utils::storeMachineEndian(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, 0); // set MAC field to 0 + HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, packetSize, hmac); + if (unlikely(! Utils::secureEq(hmac, pkt.unsafeData + packetSize, ZT_HMACSHA384_LEN))) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9891, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + } + else { + // Older versions use Poly1305 MAC (but no whole packet encryption) for HELLO. + if (likely(packetSize > ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)) { + uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE]; + Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, pkt, packetSize); + uint8_t macKey[ZT_POLY1305_KEY_SIZE]; + Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE); + Poly1305 poly1305(macKey); + poly1305.update( + pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, + packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START); + uint64_t polyMac[2]; + poly1305.finish(polyMac); + if (unlikely(mac != polyMac[0])) { + m_ctx.t->incomingPacketDropped( + cc, + 0x11bfff82, + packetId, + 0, + id, + path->address(), + hops, + Protocol::VERB_NOP, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + } + else { + m_ctx.t->incomingPacketDropped( + cc, + 0x11bfff81, + packetId, + 0, + id, + path->address(), + hops, + Protocol::VERB_NOP, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return SharedPtr(); + } + } + + // ------------------------------------------------------------------------------------------------------------------ + // This far means we passed MAC (Poly1305 or HMAC-SHA384 for newer peers) + // ------------------------------------------------------------------------------------------------------------------ + + InetAddress sentTo; + if (unlikely(pkt.rO(ii, sentTo) < 0)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9811, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return SharedPtr(); + } + + SymmetricKey& key = peer->key(); + + if (protoVersion >= 11) { + // V2.x and newer supports an encrypted section and has a new OK format. + ii += 4; // skip reserved field + if (likely((ii + 12) < packetSize)) { + AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher()); + const uint8_t* const ctrNonce = pkt.unsafeData + ii; + ii += 12; + ctr.init(ctrNonce, 0, pkt.unsafeData + ii); + ctr.crypt(pkt.unsafeData + ii, packetSize - ii); + ctr.finish(); + + ii += 2; // skip reserved field + const unsigned int dictSize = pkt.rI16(ii); + if (unlikely((ii + dictSize) > packetSize)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9815, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return peer; + } + Dictionary md; + if (! md.decode(pkt.unsafeData + ii, dictSize)) { + m_ctx.t->incomingPacketDropped( + cc, + 0x707a9816, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + hops, + Protocol::VERB_HELLO, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + return peer; + } + + if (! md.empty()) { + // TODO + } + } + } + + Protocol::newPacket( + pkt, + key.nextMessage(m_ctx.identity.address(), peer->address()), + peer->address(), + m_ctx.identity.address(), + Protocol::VERB_OK); + ii = ZT_PROTO_PACKET_PAYLOAD_START; + pkt.wI8(ii, Protocol::VERB_HELLO); + pkt.wI64(ii, packetId); + pkt.wI64(ii, timestamp); + pkt.wI8(ii, ZT_PROTO_VERSION); + pkt.wI8(ii, ZEROTIER_VERSION_MAJOR); + pkt.wI8(ii, ZEROTIER_VERSION_MINOR); + pkt.wI16(ii, ZEROTIER_VERSION_REVISION); + pkt.wO(ii, path->address()); + pkt.wI16(ii, 0); // reserved, specifies no "moons" for older versions + + if (protoVersion >= 11) { + FCV okmd; + pkt.wI16(ii, (uint16_t)okmd.size()); + pkt.wB(ii, okmd.data(), okmd.size()); + + if (unlikely((ii + ZT_HMACSHA384_LEN) > ZT_BUF_MEM_SIZE)) // sanity check, should be impossible + return SharedPtr(); + + HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, ii, pkt.unsafeData + ii); + ii += ZT_HMACSHA384_LEN; + } + + peer->setRemoteVersion(protoVersion, versionMajor, versionMinor, versionRev); + peer->send(m_ctx, cc, pkt.unsafeData, ii, path); + return peer; +} + +bool VL1::m_ERROR( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize, + Protocol::Verb& inReVerb) { #if 0 if (packetSize < (int)sizeof(Protocol::ERROR::Header)) { @@ -684,44 +940,80 @@ bool VL1::m_ERROR(CallContext &cc, const uint64_t packetId, const unsigned int a #endif } -bool VL1::m_OK(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb) +bool VL1::m_OK( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize, + Protocol::Verb& inReVerb) { - int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13; + int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13; - inReVerb = (Protocol::Verb)pkt.rI8(ii); - const uint64_t inRePacketId = pkt.rI64(ii); - if (unlikely(Buf::readOverflow(ii, packetSize))) { - m_ctx.t->incomingPacketDropped(cc, 0x4c1f1ff7, packetId, 0, identityFromPeerPtr(peer), path->address(), 0, Protocol::VERB_OK, ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); - return false; - } + inReVerb = (Protocol::Verb)pkt.rI8(ii); + const uint64_t inRePacketId = pkt.rI64(ii); + if (unlikely(Buf::readOverflow(ii, packetSize))) { + m_ctx.t->incomingPacketDropped( + cc, + 0x4c1f1ff7, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + 0, + Protocol::VERB_OK, + ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + return false; + } - if (unlikely(!m_ctx.expect->expecting(inRePacketId, cc.ticks))) { - m_ctx.t->incomingPacketDropped(cc, 0x4c1f1ff8, packetId, 0, identityFromPeerPtr(peer), path->address(), 0, Protocol::VERB_OK, ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED); - return false; - } + if (unlikely(! m_ctx.expect->expecting(inRePacketId, cc.ticks))) { + m_ctx.t->incomingPacketDropped( + cc, + 0x4c1f1ff8, + packetId, + 0, + identityFromPeerPtr(peer), + path->address(), + 0, + Protocol::VERB_OK, + ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED); + return false; + } - ZT_SPEW("got OK in-re %s (packet ID %.16llx) from %s(%s)", Protocol::verbName(inReVerb), inRePacketId, peer->address().toString().c_str(), path->address().toString().c_str()); + ZT_SPEW( + "got OK in-re %s (packet ID %.16llx) from %s(%s)", + Protocol::verbName(inReVerb), + inRePacketId, + peer->address().toString().c_str(), + path->address().toString().c_str()); - switch (inReVerb) { + switch (inReVerb) { + case Protocol::VERB_HELLO: + break; - case Protocol::VERB_HELLO: - break; + case Protocol::VERB_WHOIS: + break; - case Protocol::VERB_WHOIS: - break; + case Protocol::VERB_NETWORK_CONFIG_REQUEST: + break; - case Protocol::VERB_NETWORK_CONFIG_REQUEST: - break; + case Protocol::VERB_MULTICAST_GATHER: + break; + } - case Protocol::VERB_MULTICAST_GATHER: - break; - - } - - return true; + return true; } -bool VL1::m_WHOIS(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_WHOIS( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { #if 0 if (packetSize < (int)sizeof(Protocol::OK::Header)) { @@ -775,7 +1067,14 @@ bool VL1::m_WHOIS(CallContext &cc, const uint64_t packetId, const unsigned int a #endif } -bool VL1::m_RENDEZVOUS(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_RENDEZVOUS( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { #if 0 if (RR->topology->isRoot(peer->identity())) { @@ -823,7 +1122,14 @@ bool VL1::m_RENDEZVOUS(CallContext &cc, const uint64_t packetId, const unsigned #endif } -bool VL1::m_ECHO(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_ECHO( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { #if 0 const uint64_t packetId = Protocol::packetId(pkt,packetSize); @@ -861,7 +1167,14 @@ bool VL1::m_ECHO(CallContext &cc, const uint64_t packetId, const unsigned int au #endif } -bool VL1::m_PUSH_DIRECT_PATHS(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_PUSH_DIRECT_PATHS( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { #if 0 if (packetSize < (int)sizeof(Protocol::PUSH_DIRECT_PATHS)) { @@ -952,16 +1265,30 @@ bool VL1::m_PUSH_DIRECT_PATHS(CallContext &cc, const uint64_t packetId, const un #endif } -bool VL1::m_USER_MESSAGE(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_USER_MESSAGE( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { - // TODO - return true; + // TODO + return true; } -bool VL1::m_ENCAP(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL1::m_ENCAP( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize) { - // TODO: not implemented yet - return true; + // TODO: not implemented yet + return true; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/VL1.hpp b/core/VL1.hpp index a1dfec9ac..65fcdbefa 100644 --- a/core/VL1.hpp +++ b/core/VL1.hpp @@ -14,15 +14,15 @@ #ifndef ZT_VL1_HPP #define ZT_VL1_HPP -#include "Constants.hpp" -#include "Defragmenter.hpp" -#include "Buf.hpp" #include "Address.hpp" -#include "Protocol.hpp" -#include "Mutex.hpp" -#include "FCV.hpp" -#include "Containers.hpp" +#include "Buf.hpp" #include "CallContext.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "Defragmenter.hpp" +#include "FCV.hpp" +#include "Mutex.hpp" +#include "Protocol.hpp" #define ZT_VL1_MAX_WHOIS_WAITING_PACKETS 32 @@ -43,62 +43,124 @@ class VL2; * * This class is thread safe. */ -class VL1 -{ -public: - explicit VL1(const Context &ctx); +class VL1 { + public: + explicit VL1(const Context& ctx); - /** - * Called when a packet is received from the real network - * - * The packet data supplied to this method may be modified. Internal - * packet handler code may also take possession of it via atomic swap - * and leave the 'data' pointer NULL. The 'data' pointer and its - * contents should not be used after this call. Make a copy if the - * data might still be needed. - * - * @param localSocket Local I/O socket as supplied by external code - * @param fromAddr Internet IP address of origin - * @param data Packet data - * @param len Packet length - */ - void onRemotePacket(CallContext &cc, int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, unsigned int len) noexcept; + /** + * Called when a packet is received from the real network + * + * The packet data supplied to this method may be modified. Internal + * packet handler code may also take possession of it via atomic swap + * and leave the 'data' pointer NULL. The 'data' pointer and its + * contents should not be used after this call. Make a copy if the + * data might still be needed. + * + * @param localSocket Local I/O socket as supplied by external code + * @param fromAddr Internet IP address of origin + * @param data Packet data + * @param len Packet length + */ + void onRemotePacket( + CallContext& cc, + int64_t localSocket, + const InetAddress& fromAddr, + SharedPtr& data, + unsigned int len) noexcept; -private: - void m_relay(CallContext &cc, const SharedPtr< Path > &path, Address destination, SharedPtr< Buf > &pkt, int pktSize); - void m_sendPendingWhois(CallContext &cc); - SharedPtr< Peer > m_HELLO(CallContext &cc, const SharedPtr< Path > &path, Buf &pkt, int packetSize); - bool m_ERROR(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); - bool m_OK(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); - bool m_WHOIS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_RENDEZVOUS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_ECHO(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_PUSH_DIRECT_PATHS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_USER_MESSAGE(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_ENCAP(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); + private: + void m_relay(CallContext& cc, const SharedPtr& path, Address destination, SharedPtr& pkt, int pktSize); + void m_sendPendingWhois(CallContext& cc); + SharedPtr m_HELLO(CallContext& cc, const SharedPtr& path, Buf& pkt, int packetSize); + bool m_ERROR( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize, + Protocol::Verb& inReVerb); + bool m_OK( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize, + Protocol::Verb& inReVerb); + bool m_WHOIS( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_RENDEZVOUS( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_ECHO( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_PUSH_DIRECT_PATHS( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_USER_MESSAGE( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_ENCAP( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + const SharedPtr& peer, + Buf& pkt, + int packetSize); - const Context &m_ctx; + const Context& m_ctx; - // Defragmentation engine for handling inbound packets with more than one fragment. - Defragmenter< ZT_MAX_PACKET_FRAGMENTS > m_inputPacketAssembler; + // Defragmentation engine for handling inbound packets with more than one fragment. + Defragmenter m_inputPacketAssembler; - // Queue of outbound WHOIS reqeusts and packets waiting on them. - struct p_WhoisQueueItem - { - ZT_INLINE p_WhoisQueueItem() : lastRetry(0), retries(0), waitingPacketCount(0) - {} + // Queue of outbound WHOIS reqeusts and packets waiting on them. + struct p_WhoisQueueItem { + ZT_INLINE p_WhoisQueueItem() : lastRetry(0), retries(0), waitingPacketCount(0) + { + } - int64_t lastRetry; - unsigned int retries; - unsigned int waitingPacketCount; - unsigned int waitingPacketSize[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; - SharedPtr< Buf > waitingPacket[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; - }; + int64_t lastRetry; + unsigned int retries; + unsigned int waitingPacketCount; + unsigned int waitingPacketSize[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; + SharedPtr waitingPacket[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; + }; - Map< Address, p_WhoisQueueItem > m_whoisQueue; - Mutex m_whoisQueue_l; + Map m_whoisQueue; + Mutex m_whoisQueue_l; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/VL2.cpp b/core/VL2.cpp index be519f36f..d180c7f99 100644 --- a/core/VL2.cpp +++ b/core/VL2.cpp @@ -12,59 +12,130 @@ /****/ #include "VL2.hpp" + #include "Context.hpp" -#include "VL1.hpp" -#include "Topology.hpp" -#include "Peer.hpp" -#include "Path.hpp" -#include "Network.hpp" #include "MAC.hpp" +#include "Network.hpp" +#include "Path.hpp" +#include "Peer.hpp" +#include "Topology.hpp" +#include "VL1.hpp" namespace ZeroTier { -VL2::VL2(const Context &ctx): - m_ctx(ctx) +VL2::VL2(const Context& ctx) : m_ctx(ctx) { } -void VL2::onLocalEthernet(CallContext &cc, const SharedPtr< Network > &network, const MAC &from, const MAC &to, const unsigned int etherType, unsigned int vlanId, SharedPtr< Buf > &data, unsigned int len) +void VL2::onLocalEthernet( + CallContext& cc, + const SharedPtr& network, + const MAC& from, + const MAC& to, + const unsigned int etherType, + unsigned int vlanId, + SharedPtr& data, + unsigned int len) { } -bool VL2::m_FRAME(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_FRAME( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_EXT_FRAME(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_EXT_FRAME( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_MULTICAST_LIKE(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_LIKE( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_NETWORK_CREDENTIALS(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CREDENTIALS( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_NETWORK_CONFIG_REQUEST(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CONFIG_REQUEST( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_NETWORK_CONFIG(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CONFIG( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_MULTICAST_GATHER(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_GATHER( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_MULTICAST_FRAME_deprecated(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_FRAME_deprecated( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -bool VL2::m_MULTICAST(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST( + CallContext& cc, + const uint64_t packetId, + const unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize) { } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/core/VL2.hpp b/core/VL2.hpp index 5e1650df3..6ff84792f 100644 --- a/core/VL2.hpp +++ b/core/VL2.hpp @@ -14,14 +14,14 @@ #ifndef ZT_VL2_HPP #define ZT_VL2_HPP -#include "Constants.hpp" -#include "Buf.hpp" #include "Address.hpp" -#include "Protocol.hpp" -#include "Mutex.hpp" -#include "FCV.hpp" -#include "Containers.hpp" +#include "Buf.hpp" #include "CallContext.hpp" +#include "Constants.hpp" +#include "Containers.hpp" +#include "FCV.hpp" +#include "Mutex.hpp" +#include "Protocol.hpp" namespace ZeroTier { @@ -32,41 +32,111 @@ class VL1; class Network; class MAC; -class VL2 -{ - friend class VL1; +class VL2 { + friend class VL1; -public: - explicit VL2(const Context &ctx); + public: + explicit VL2(const Context& ctx); - /** - * Called when a packet comes from a local Ethernet tap - * - * @param network Which network's TAP did this packet come from? - * @param from Originating MAC address - * @param to Destination MAC address - * @param etherType Ethernet packet type - * @param vlanId VLAN ID or 0 if none - * @param data Ethernet payload - * @param len Frame length - */ - void onLocalEthernet(CallContext &cc, const SharedPtr< Network > &network, const MAC &from, const MAC &to, unsigned int etherType, unsigned int vlanId, SharedPtr< Buf > &data, unsigned int len); + /** + * Called when a packet comes from a local Ethernet tap + * + * @param network Which network's TAP did this packet come from? + * @param from Originating MAC address + * @param to Destination MAC address + * @param etherType Ethernet packet type + * @param vlanId VLAN ID or 0 if none + * @param data Ethernet payload + * @param len Frame length + */ + void onLocalEthernet( + CallContext& cc, + const SharedPtr& network, + const MAC& from, + const MAC& to, + unsigned int etherType, + unsigned int vlanId, + SharedPtr& data, + unsigned int len); -protected: - bool m_FRAME(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_EXT_FRAME(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_LIKE(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CREDENTIALS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CONFIG_REQUEST(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CONFIG(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_GATHER(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_FRAME_deprecated(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); - bool m_MULTICAST(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize); + protected: + bool m_FRAME( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_EXT_FRAME( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_MULTICAST_LIKE( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_NETWORK_CREDENTIALS( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_NETWORK_CONFIG_REQUEST( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_NETWORK_CONFIG( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_MULTICAST_GATHER( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_MULTICAST_FRAME_deprecated( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); + bool m_MULTICAST( + CallContext& cc, + uint64_t packetId, + unsigned int auth, + const SharedPtr& path, + SharedPtr& peer, + Buf& pkt, + int packetSize); -private: - const Context &m_ctx; + private: + const Context& m_ctx; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/core/version.h.in b/core/version.h.in index cc43aed1b..0b2ec2501 100644 --- a/core/version.h.in +++ b/core/version.h.in @@ -17,17 +17,17 @@ /** * Major version */ -#define ZEROTIER_VERSION_MAJOR @ZEROTIER_VERSION_MAJOR@ +#define ZEROTIER_VERSION_MAJOR @ZEROTIER_VERSION_MAJOR @ /** * Minor version */ -#define ZEROTIER_VERSION_MINOR @ZEROTIER_VERSION_MINOR@ +#define ZEROTIER_VERSION_MINOR @ZEROTIER_VERSION_MINOR @ /** * Revision */ -#define ZEROTIER_VERSION_REVISION @ZEROTIER_VERSION_REVISION@ +#define ZEROTIER_VERSION_REVISION @ZEROTIER_VERSION_REVISION @ /** * Build version @@ -36,6 +36,6 @@ * to force a minor update without an actual version number change. It's * not part of the actual release version number. */ -#define ZEROTIER_VERSION_BUILD @ZEROTIER_VERSION_BUILD@ +#define ZEROTIER_VERSION_BUILD @ZEROTIER_VERSION_BUILD @ #endif diff --git a/core/zerotier.h b/core/zerotier.h index b63809572..38d22dd37 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -257,10 +257,9 @@ extern "C" { * * Do not change these integer values. They're protocol constants. */ -enum ZT_IdentityType -{ - ZT_IDENTITY_TYPE_C25519 = 0, /* C25519/Ed25519 */ - ZT_IDENTITY_TYPE_P384 = 1 /* Combined C25519/NIST-P-384 key */ +enum ZT_IdentityType { + ZT_IDENTITY_TYPE_C25519 = 0, /* C25519/Ed25519 */ + ZT_IDENTITY_TYPE_P384 = 1 /* Combined C25519/NIST-P-384 key */ }; /** @@ -284,37 +283,37 @@ typedef void ZT_Locator; * is correct for the platform. If it's not correct, a platform ifdef * will be needed. */ -typedef struct { uint64_t bits[ZT_SOCKADDR_STORAGE_SIZE / 8]; } ZT_InetAddress; +typedef struct { + uint64_t bits[ZT_SOCKADDR_STORAGE_SIZE / 8]; +} ZT_InetAddress; /** * IP scope types as identified by InetAddress. */ -enum ZT_InetAddress_IpScope -{ - ZT_IP_SCOPE_NONE = 0, // NULL or not an IP address - ZT_IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs - ZT_IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. - ZT_IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" - ZT_IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) - ZT_IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL - ZT_IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges - ZT_IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. +enum ZT_InetAddress_IpScope { + ZT_IP_SCOPE_NONE = 0, // NULL or not an IP address + ZT_IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs + ZT_IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. + ZT_IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" + ZT_IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) + ZT_IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL + ZT_IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges + ZT_IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. }; /** * Full identity fingerprint with address and 384-bit hash of public key(s) */ -typedef struct -{ - /** - * Short address (only least significant 40 bits are used) - */ - uint64_t address; +typedef struct { + /** + * Short address (only least significant 40 bits are used) + */ + uint64_t address; - /** - * 384-bit hash of identity public key(s) - */ - uint8_t hash[48]; + /** + * 384-bit hash of identity public key(s) + */ + uint8_t hash[48]; } ZT_Fingerprint; /** @@ -345,135 +344,133 @@ typedef struct /** * Certificate can sign things (general). */ -#define ZT_CERTIFICATE_USAGE_DIGITAL_SIGNATURE 0x00000001U +#define ZT_CERTIFICATE_USAGE_DIGITAL_SIGNATURE 0x00000001U /** * Certificate can verify signatures to verify actions. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_NON_REPUDIATION 0x00000002U +#define ZT_CERTIFICATE_USAGE_NON_REPUDIATION 0x00000002U /** * Certificate's key can encipher other keys. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_KEY_ENCIPHERMENT 0x00000004U +#define ZT_CERTIFICATE_USAGE_KEY_ENCIPHERMENT 0x00000004U /** * Certificate's key can encipher data. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_DATA_ENCIPHERMENT 0x00000008U +#define ZT_CERTIFICATE_USAGE_DATA_ENCIPHERMENT 0x00000008U /** * Certificate's key can be used for Diffie-Hellman style key agreemtn. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_KEY_AGREEMENT 0x00000010U +#define ZT_CERTIFICATE_USAGE_KEY_AGREEMENT 0x00000010U /** * Certificate can sign other certificates. */ -#define ZT_CERTIFICATE_USAGE_CERTIFICATE_SIGNING 0x00000020U +#define ZT_CERTIFICATE_USAGE_CERTIFICATE_SIGNING 0x00000020U /** * Certificate can revoke signatures. */ -#define ZT_CERTIFICATE_USAGE_CRL_SIGNING 0x00000040U +#define ZT_CERTIFICATE_USAGE_CRL_SIGNING 0x00000040U /** * Certificate can sign executable code. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE 0x00000080U +#define ZT_CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE 0x00000080U /** * Certificate's public key can be used for a timestamp service. * * (not used in ZeroTier) */ -#define ZT_CERTIFICATE_USAGE_TIMESTAMPING 0x00000100U +#define ZT_CERTIFICATE_USAGE_TIMESTAMPING 0x00000100U /** * Certificate can enumerate a set of ZeroTier root nodes. */ -#define ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET 0x00000200U +#define ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET 0x00000200U /** * Errors returned by functions that verify or handle certificates. */ -enum ZT_CertificateError -{ - /** - * No error (certificate is valid or operation was successful) - */ - ZT_CERTIFICATE_ERROR_NONE = 0, +enum ZT_CertificateError { + /** + * No error (certificate is valid or operation was successful) + */ + ZT_CERTIFICATE_ERROR_NONE = 0, - /** - * Certificate format is invalid or required fields are missing - */ - ZT_CERTIFICATE_ERROR_INVALID_FORMAT = 1, + /** + * Certificate format is invalid or required fields are missing + */ + ZT_CERTIFICATE_ERROR_INVALID_FORMAT = 1, - /** - * One or more identities in the certificate are invalid or fail consistency check - */ - ZT_CERTIFICATE_ERROR_INVALID_IDENTITY = 2, + /** + * One or more identities in the certificate are invalid or fail consistency check + */ + ZT_CERTIFICATE_ERROR_INVALID_IDENTITY = 2, - /** - * Certificate primary signature is invalid - */ - ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE = 3, + /** + * Certificate primary signature is invalid + */ + ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE = 3, - /** - * Full chain validation of certificate failed - */ - ZT_CERTIFICATE_ERROR_INVALID_CHAIN = 4, + /** + * Full chain validation of certificate failed + */ + ZT_CERTIFICATE_ERROR_INVALID_CHAIN = 4, - /** - * One or more signed components (e.g. a Locator) has an invalid signature. - */ - ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE = 5, + /** + * One or more signed components (e.g. a Locator) has an invalid signature. + */ + ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE = 5, - /** - * Unique ID proof signature in subject was not valid. - */ - ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF = 6, + /** + * Unique ID proof signature in subject was not valid. + */ + ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF = 6, - /** - * Certificate is missing a required field - */ - ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS = 7, + /** + * Certificate is missing a required field + */ + ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS = 7, - /** - * Certificate is expired or not yet in effect - */ - ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW = 8, + /** + * Certificate is expired or not yet in effect + */ + ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW = 8, - /** - * Certificate explicitly revoked - */ - ZT_CERTIFICATE_ERROR_REVOKED = 9 + /** + * Certificate explicitly revoked + */ + ZT_CERTIFICATE_ERROR_REVOKED = 9 }; /** * Public key signing algorithm for certificates */ -enum ZT_CertificatePublicKeyAlgorithm -{ - /** - * Nil value indicating no signature. - */ - ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE = 0, +enum ZT_CertificatePublicKeyAlgorithm { + /** + * Nil value indicating no signature. + */ + ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE = 0, - /** - * ECDSA with the NIST P-384 curve. - */ - ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384 = 1 + /** + * ECDSA with the NIST P-384 curve. + */ + ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384 = 1 }; /** @@ -509,121 +506,117 @@ enum ZT_CertificatePublicKeyAlgorithm * These fields are all optional and are all taken from the * most common fields present in X509 certificates. */ -typedef struct -{ - char serialNo[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char commonName[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char country[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char organization[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char unit[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char locality[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char province[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char streetAddress[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char postalCode[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char email[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char url[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char host[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; +typedef struct { + char serialNo[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char commonName[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char country[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char organization[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char unit[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char locality[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char province[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char streetAddress[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char postalCode[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char email[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char url[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char host[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; } ZT_Certificate_Name; /** * Identity and optional locator to help find a node on physical networks. */ -typedef struct -{ - /** - * Identity (never NULL) - */ - const ZT_Identity *identity; +typedef struct { + /** + * Identity (never NULL) + */ + const ZT_Identity* identity; - /** - * Locator (NULL if no locator included) - */ - const ZT_Locator *locator; + /** + * Locator (NULL if no locator included) + */ + const ZT_Locator* locator; } ZT_Certificate_Identity; /** * ID and primary controller for a network */ -typedef struct -{ - /** - * Network ID - */ - uint64_t id; +typedef struct { + /** + * Network ID + */ + uint64_t id; - /** - * Full fingerprint of primary controller - */ - ZT_Fingerprint controller; + /** + * Full fingerprint of primary controller + */ + ZT_Fingerprint controller; } ZT_Certificate_Network; /** * Identification certificate subject */ -typedef struct -{ - /** - * Timestamp of subject, can also be a revision ID for this subject's name. - */ - int64_t timestamp; +typedef struct { + /** + * Timestamp of subject, can also be a revision ID for this subject's name. + */ + int64_t timestamp; - /** - * Identities and optional locators of nodes - */ - ZT_Certificate_Identity *identities; + /** + * Identities and optional locators of nodes + */ + ZT_Certificate_Identity* identities; - /** - * Networks owned by this entity - */ - ZT_Certificate_Network *networks; + /** + * Networks owned by this entity + */ + ZT_Certificate_Network* networks; - /** - * URLs that can be consulted for updates to this certificate. - */ - const char **updateURLs; + /** + * URLs that can be consulted for updates to this certificate. + */ + const char** updateURLs; - /** - * Number of identities - */ - unsigned int identityCount; + /** + * Number of identities + */ + unsigned int identityCount; - /** - * Number of networks - */ - unsigned int networkCount; + /** + * Number of networks + */ + unsigned int networkCount; - /** - * Number of update URLs - */ - unsigned int updateURLCount; + /** + * Number of update URLs + */ + unsigned int updateURLCount; - /** - * Information about owner of items. - */ - ZT_Certificate_Name name; + /** + * Information about owner of items. + */ + ZT_Certificate_Name name; - /** - * Globally unique ID for this subject - * - * This is actually a public key and is generated the same way as a normal - * certificate public key. - */ - uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; + /** + * Globally unique ID for this subject + * + * This is actually a public key and is generated the same way as a normal + * certificate public key. + */ + uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; - /** - * Signature proving ownership of unique ID. - */ - uint8_t uniqueIdSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; + /** + * Signature proving ownership of unique ID. + */ + uint8_t uniqueIdSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; - /** - * Size of unique ID in bytes or 0 if none. - */ - unsigned int uniqueIdSize; + /** + * Size of unique ID in bytes or 0 if none. + */ + unsigned int uniqueIdSize; - /** - * Proof signature size or 0 if none. - */ - unsigned int uniqueIdSignatureSize; + /** + * Proof signature size or 0 if none. + */ + unsigned int uniqueIdSignatureSize; } ZT_Certificate_Subject; /** @@ -636,166 +629,162 @@ typedef struct * possible, small, and secure. X509 is both bloated and a security * disaster as it's very hard to implement correctly. */ -typedef struct -{ - /** - * Serial number, a SHA384 hash of this certificate (minus signature). - */ - uint8_t serialNo[ZT_CERTIFICATE_HASH_SIZE]; +typedef struct { + /** + * Serial number, a SHA384 hash of this certificate (minus signature). + */ + uint8_t serialNo[ZT_CERTIFICATE_HASH_SIZE]; - /** - * Certificate usage flags. - */ - uint64_t usageFlags; + /** + * Certificate usage flags. + */ + uint64_t usageFlags; - /** - * Certificate timestamp in milliseconds since epoch. - */ - int64_t timestamp; + /** + * Certificate timestamp in milliseconds since epoch. + */ + int64_t timestamp; - /** - * Valid time range: not before, not after. - */ - int64_t validity[2]; + /** + * Valid time range: not before, not after. + */ + int64_t validity[2]; - /** - * Subject of certificate - */ - ZT_Certificate_Subject subject; + /** + * Subject of certificate + */ + ZT_Certificate_Subject subject; - /** - * Issuer certificate serial number. - */ - uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE]; + /** + * Issuer certificate serial number. + */ + uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE]; - /** - * Public key of issuer certificate. - */ - uint8_t issuerPublicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; + /** + * Public key of issuer certificate. + */ + uint8_t issuerPublicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; - /** - * Certificate public key (first byte is ZT_CertificatePublicKeyAlgorithm) - */ - uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; + /** + * Certificate public key (first byte is ZT_CertificatePublicKeyAlgorithm) + */ + uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE]; - /** - * Size of issuer public key. - */ - unsigned int issuerPublicKeySize; + /** + * Size of issuer public key. + */ + unsigned int issuerPublicKeySize; - /** - * Size of public key in bytes - */ - unsigned int publicKeySize; + /** + * Size of public key in bytes + */ + unsigned int publicKeySize; - /** - * Extended attributes set by issuer (in Dictionary format, NULL if none) - */ - const uint8_t *extendedAttributes; + /** + * Extended attributes set by issuer (in Dictionary format, NULL if none) + */ + const uint8_t* extendedAttributes; - /** - * Size of extended attributes field in bytes - */ - unsigned int extendedAttributesSize; + /** + * Size of extended attributes field in bytes + */ + unsigned int extendedAttributesSize; - /** - * Signature by issuer. - */ - uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; + /** + * Signature by issuer. + */ + uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; - /** - * Size of signature in bytes. - */ - unsigned int signatureSize; + /** + * Size of signature in bytes. + */ + unsigned int signatureSize; - /** - * Maximum path length from this certificate toward further certificates. - * - * Subjects may sign other certificates whose path lengths are less than - * this value. A value of zero indicates that no identification certificates - * may be signed (not a CA). - */ - unsigned int maxPathLength; + /** + * Maximum path length from this certificate toward further certificates. + * + * Subjects may sign other certificates whose path lengths are less than + * this value. A value of zero indicates that no identification certificates + * may be signed (not a CA). + */ + unsigned int maxPathLength; } ZT_Certificate; /** * A revocation for one or more certificates. */ -typedef struct -{ - /** - * Certificate issuing this revocation. - */ - uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE]; +typedef struct { + /** + * Certificate issuing this revocation. + */ + uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE]; - /** - * Timestamp in milliseconds since epoch. - */ - int64_t timestamp; + /** + * Timestamp in milliseconds since epoch. + */ + int64_t timestamp; - /** - * Revoked certificate serials. - */ - uint8_t serials[ZT_CERTIFICATE_REVOCATION_MAX_CERTIFICATES][ZT_CERTIFICATE_HASH_SIZE]; + /** + * Revoked certificate serials. + */ + uint8_t serials[ZT_CERTIFICATE_REVOCATION_MAX_CERTIFICATES][ZT_CERTIFICATE_HASH_SIZE]; - /** - * Short optional human-readable reason or URL. - */ - char reason[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + /** + * Short optional human-readable reason or URL. + */ + char reason[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - /** - * Signature of revocation by revoking issuer. - */ - uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; + /** + * Signature of revocation by revoking issuer. + */ + uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; - /** - * Number of revoked certificates. - */ - unsigned int count; + /** + * Number of revoked certificates. + */ + unsigned int count; - /** - * Size of signature in bytes. - */ - unsigned int signatureSize; + /** + * Size of signature in bytes. + */ + unsigned int signatureSize; } ZT_CertificateRevocation; /** * A list of certificates */ -typedef struct -{ - /** - * Function that is called to free this list (called by ZT_freeQueryResult) - */ - void (*freeFunction)(const void *); +typedef struct { + /** + * Function that is called to free this list (called by ZT_freeQueryResult) + */ + void (*freeFunction)(const void*); - /** - * Array of pointers to certificates - */ - const ZT_Certificate *const *certs; + /** + * Array of pointers to certificates + */ + const ZT_Certificate* const* certs; - /** - * Array of local trust flags for each certificate - */ - const unsigned int *localTrust; + /** + * Array of local trust flags for each certificate + */ + const unsigned int* localTrust; - /** - * Number of certificates - */ - unsigned long certCount; + /** + * Number of certificates + */ + unsigned long certCount; } ZT_CertificateList; /** * Credential type IDs */ -enum ZT_CredentialType -{ - ZT_CREDENTIAL_TYPE_NULL = 0, - ZT_CREDENTIAL_TYPE_COM = 1, - ZT_CREDENTIAL_TYPE_CAPABILITY = 2, - ZT_CREDENTIAL_TYPE_TAG = 3, - ZT_CREDENTIAL_TYPE_COO = 4, - ZT_CREDENTIAL_TYPE_REVOCATION = 6 +enum ZT_CredentialType { + ZT_CREDENTIAL_TYPE_NULL = 0, + ZT_CREDENTIAL_TYPE_COM = 1, + ZT_CREDENTIAL_TYPE_CAPABILITY = 2, + ZT_CREDENTIAL_TYPE_TAG = 3, + ZT_CREDENTIAL_TYPE_COO = 4, + ZT_CREDENTIAL_TYPE_REVOCATION = 6 }; /** @@ -807,17 +796,16 @@ enum ZT_CredentialType * Most of these are not currently implemented and are just reserved * for future use. */ -enum ZT_EndpointType -{ - ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ - ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ - ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ - ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ - ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ - ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ - ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP (the default and original) */ - ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ - ZT_ENDPOINT_TYPE_IP_TCP_WS = 8 /* IP/TCP web sockets */ +enum ZT_EndpointType { + ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ + ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ + ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ + ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ + ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ + ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ + ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP (the default and original) */ + ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ + ZT_ENDPOINT_TYPE_IP_TCP_WS = 8 /* IP/TCP web sockets */ }; /** @@ -828,17 +816,17 @@ enum ZT_EndpointType /** * Flag indicating that VL1 tracing should be generated */ -#define ZT_TRACE_FLAG_VL1 0x01 +#define ZT_TRACE_FLAG_VL1 0x01 /** * Flag indicating that VL2 (virtual network) tracing should be generated */ -#define ZT_TRACE_FLAG_VL2 0x02 +#define ZT_TRACE_FLAG_VL2 0x02 /** * Flag indicating that VL2 network filter tracing should be generated (separate because this can be very verbose) */ -#define ZT_TRACE_FLAG_VL2_FILTER 0x04 +#define ZT_TRACE_FLAG_VL2_FILTER 0x04 /** * Flag indicating that VL2 multicast propagation should be reported @@ -850,98 +838,94 @@ enum ZT_EndpointType * * All trace event structures start with a size and type. */ -enum ZT_TraceEventType -{ - ZT_TRACE_UNEXPECTED_ERROR = 0, - ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1, - ZT_TRACE_VL1_TRYING_NEW_PATH = 2, - ZT_TRACE_VL1_LEARNED_NEW_PATH = 3, - ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4, - ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100, - ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101, - ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102, - ZT_TRACE_VL2_NETWORK_FILTER = 103, - ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED = 104, +enum ZT_TraceEventType { + ZT_TRACE_UNEXPECTED_ERROR = 0, + ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1, + ZT_TRACE_VL1_TRYING_NEW_PATH = 2, + ZT_TRACE_VL1_LEARNED_NEW_PATH = 3, + ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4, + ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100, + ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101, + ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102, + ZT_TRACE_VL2_NETWORK_FILTER = 103, + ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED = 104, }; /** * Trace VL1 packet drop reasons */ -enum ZT_TracePacketDropReason -{ - ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0, - ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1, - ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2, - ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3, - ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4, - ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5, - ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6, - ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7, - ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED = 8 +enum ZT_TracePacketDropReason { + ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0, + ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1, + ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3, + ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5, + ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6, + ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7, + ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED = 8 }; /** * Trace VL2 frame drop reasons */ -enum ZT_TraceFrameDropReason -{ - ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0, - ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1, - ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2, - ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3, - ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4, - ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5, - ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION = 6, - ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7 +enum ZT_TraceFrameDropReason { + ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0, + ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1, + ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2, + ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3, + ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4, + ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5, + ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION = 6, + ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7 }; /** * Reasons for credential rejection */ -enum ZT_TraceCredentialRejectionReason -{ - ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED = 1, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4 +enum ZT_TraceCredentialRejectionReason { + ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED = 1, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4 }; -#define ZT_TRACE_FIELD_TYPE "t" -#define ZT_TRACE_FIELD_CODE_LOCATION "c" -#define ZT_TRACE_FIELD_ENDPOINT "e" -#define ZT_TRACE_FIELD_OLD_ENDPOINT "oe" -#define ZT_TRACE_FIELD_NEW_ENDPOINT "ne" -#define ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT "te" -#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID "ti" -#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB "tv" -#define ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT "tp" -#define ZT_TRACE_FIELD_MESSAGE "m" -#define ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE "rs" -#define ZT_TRACE_FIELD_IDENTITY_FINGERPRINT "f" -#define ZT_TRACE_FIELD_PACKET_ID "p" -#define ZT_TRACE_FIELD_PACKET_VERB "v" -#define ZT_TRACE_FIELD_PACKET_HOPS "h" -#define ZT_TRACE_FIELD_NETWORK_ID "n" -#define ZT_TRACE_FIELD_REASON "r" -#define ZT_TRACE_FIELD_SOURCE_MAC "sm" -#define ZT_TRACE_FIELD_DEST_MAC "dm" -#define ZT_TRACE_FIELD_ETHERTYPE "et" -#define ZT_TRACE_FIELD_VLAN_ID "vlid" -#define ZT_TRACE_FIELD_FRAME_LENGTH "fl" -#define ZT_TRACE_FIELD_FRAME_DATA "fd" -#define ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT "crs" -#define ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG "rL" -#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG "caRL" -#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID "caID" -#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP "caTS" -#define ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS "sz" -#define ZT_TRACE_FIELD_DEST_ZT_ADDRESS "dz" -#define ZT_TRACE_FIELD_RULE_FLAG_NOTEE "rNT" -#define ZT_TRACE_FIELD_RULE_FLAG_INBOUND "rIN" -#define ZT_TRACE_FIELD_RULE_FLAG_ACCEPT "rACC" -#define ZT_TRACE_FIELD_CREDENTIAL_ID "crID" -#define ZT_TRACE_FIELD_CREDENTIAL_TYPE "crT" -#define ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP "crTS" +#define ZT_TRACE_FIELD_TYPE "t" +#define ZT_TRACE_FIELD_CODE_LOCATION "c" +#define ZT_TRACE_FIELD_ENDPOINT "e" +#define ZT_TRACE_FIELD_OLD_ENDPOINT "oe" +#define ZT_TRACE_FIELD_NEW_ENDPOINT "ne" +#define ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT "te" +#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID "ti" +#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB "tv" +#define ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT "tp" +#define ZT_TRACE_FIELD_MESSAGE "m" +#define ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE "rs" +#define ZT_TRACE_FIELD_IDENTITY_FINGERPRINT "f" +#define ZT_TRACE_FIELD_PACKET_ID "p" +#define ZT_TRACE_FIELD_PACKET_VERB "v" +#define ZT_TRACE_FIELD_PACKET_HOPS "h" +#define ZT_TRACE_FIELD_NETWORK_ID "n" +#define ZT_TRACE_FIELD_REASON "r" +#define ZT_TRACE_FIELD_SOURCE_MAC "sm" +#define ZT_TRACE_FIELD_DEST_MAC "dm" +#define ZT_TRACE_FIELD_ETHERTYPE "et" +#define ZT_TRACE_FIELD_VLAN_ID "vlid" +#define ZT_TRACE_FIELD_FRAME_LENGTH "fl" +#define ZT_TRACE_FIELD_FRAME_DATA "fd" +#define ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT "crs" +#define ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG "rL" +#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG "caRL" +#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID "caID" +#define ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP "caTS" +#define ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS "sz" +#define ZT_TRACE_FIELD_DEST_ZT_ADDRESS "dz" +#define ZT_TRACE_FIELD_RULE_FLAG_NOTEE "rNT" +#define ZT_TRACE_FIELD_RULE_FLAG_INBOUND "rIN" +#define ZT_TRACE_FIELD_RULE_FLAG_ACCEPT "rACC" +#define ZT_TRACE_FIELD_CREDENTIAL_ID "crID" +#define ZT_TRACE_FIELD_CREDENTIAL_TYPE "crT" +#define ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP "crTS" /** * Function return code: OK (0) or error results @@ -951,61 +935,60 @@ enum ZT_TraceCredentialRejectionReason * indicate serious problems like an inaccessible data store or a compile * problem. */ -enum ZT_ResultCode -{ - /** - * Operation completed normally - */ - ZT_RESULT_OK = 0, +enum ZT_ResultCode { + /** + * Operation completed normally + */ + ZT_RESULT_OK = 0, - /* Fatal errors (>100, <1000) */ + /* Fatal errors (>100, <1000) */ - /** - * Ran out of memory - */ - ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, + /** + * Ran out of memory + */ + ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, - /** - * Data store is not writable or has failed - */ - ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, + /** + * Data store is not writable or has failed + */ + ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, - /** - * Internal error fatal to the instance - */ - ZT_RESULT_FATAL_ERROR_INTERNAL = 102, + /** + * Internal error fatal to the instance + */ + ZT_RESULT_FATAL_ERROR_INTERNAL = 102, - /* Non-fatal errors (>1000) */ + /* Non-fatal errors (>1000) */ - /** - * Network ID not valid - */ - ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, + /** + * Network ID not valid + */ + ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, - /** - * The requested operation is not supported on this version or build - */ - ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, + /** + * The requested operation is not supported on this version or build + */ + ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, - /** - * The requested operation was given a bad parameter or was called in an invalid state - */ - ZT_RESULT_ERROR_BAD_PARAMETER = 1002, + /** + * The requested operation was given a bad parameter or was called in an invalid state + */ + ZT_RESULT_ERROR_BAD_PARAMETER = 1002, - /** - * A credential or other object was supplied that failed cryptographic signature or integrity check - */ - ZT_RESULT_ERROR_INVALID_CREDENTIAL = 1003, + /** + * A credential or other object was supplied that failed cryptographic signature or integrity check + */ + ZT_RESULT_ERROR_INVALID_CREDENTIAL = 1003, - /** - * An object collides with another object in some way (meaning is object-specific) - */ - ZT_RESULT_ERROR_COLLIDING_OBJECT = 1004, + /** + * An object collides with another object in some way (meaning is object-specific) + */ + ZT_RESULT_ERROR_COLLIDING_OBJECT = 1004, - /** - * An internal error occurred, but one that is not fatal to the whole instance - */ - ZT_RESULT_ERROR_INTERNAL = 1005 + /** + * An internal error occurred, but one that is not fatal to the whole instance + */ + ZT_RESULT_ERROR_INTERNAL = 1005 }; /** @@ -1014,83 +997,82 @@ enum ZT_ResultCode * @param x Result code * @return True if result code indicates a fatal error */ -#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100)&&(((int)(x)) < 1000)) +#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100) && (((int)(x)) < 1000)) /** * Status codes sent to status update callback when things happen */ -enum ZT_Event -{ - /** - * Node has been initialized - * - * This is the first event generated, and is always sent. It may occur - * before Node's constructor returns. - * - * Meta-data: none - */ - ZT_EVENT_UP = 0, +enum ZT_Event { + /** + * Node has been initialized + * + * This is the first event generated, and is always sent. It may occur + * before Node's constructor returns. + * + * Meta-data: none + */ + ZT_EVENT_UP = 0, - /** - * Node appears offline - * - * This indicates that the node doesn't seem to be able to reach anything, - * or hasn't for a while. It's not a hard instantaneous thing. - * - * Meta-data: none - */ - ZT_EVENT_OFFLINE = 1, + /** + * Node appears offline + * + * This indicates that the node doesn't seem to be able to reach anything, + * or hasn't for a while. It's not a hard instantaneous thing. + * + * Meta-data: none + */ + ZT_EVENT_OFFLINE = 1, - /** - * Node appears online - * - * This indicates that the node was offline but now seems to be able to - * reach something. Like OFFLINE it's not a hard instantaneous thing but - * more of an indicator for UI reporting purposes. - * - * Meta-data: none - */ - ZT_EVENT_ONLINE = 2, + /** + * Node appears online + * + * This indicates that the node was offline but now seems to be able to + * reach something. Like OFFLINE it's not a hard instantaneous thing but + * more of an indicator for UI reporting purposes. + * + * Meta-data: none + */ + ZT_EVENT_ONLINE = 2, - /** - * Node is shutting down - * - * This is generated within Node's destructor when it is being shut down. - * It's done for convenience in case you want to clean up anything during - * node shutdown in your node event handler. - * - * Meta-data: none - */ - ZT_EVENT_DOWN = 3, + /** + * Node is shutting down + * + * This is generated within Node's destructor when it is being shut down. + * It's done for convenience in case you want to clean up anything during + * node shutdown in your node event handler. + * + * Meta-data: none + */ + ZT_EVENT_DOWN = 3, - /* 4 once signaled identity collision but this is no longer an error */ + /* 4 once signaled identity collision but this is no longer an error */ - /** - * Trace (debugging) message - * - * These events are only generated if this is a TRACE-enabled build. - * This is for local debug traces, not remote trace diagnostics. The - * supplied Dictionary will always be null-terminated. - * - * Meta-data: null-terminated Dictionary containing trace info - */ - ZT_EVENT_TRACE = 5, + /** + * Trace (debugging) message + * + * These events are only generated if this is a TRACE-enabled build. + * This is for local debug traces, not remote trace diagnostics. The + * supplied Dictionary will always be null-terminated. + * + * Meta-data: null-terminated Dictionary containing trace info + */ + ZT_EVENT_TRACE = 5, - /** - * VERB_USER_MESSAGE received - * - * These are generated when a VERB_USER_MESSAGE packet is received via - * ZeroTier VL1. This can be used for below-VL2 in-band application - * specific signaling over the ZeroTier protocol. - * - * It's up to you to ensure that you handle these in a way that does - * not introduce a remote security vulnerability into your app! If - * your USER_MESSAGE code has a buffer overflow or other vulnerability - * then your app will be vulnerable and this is not ZT's fault. :) - * - * Meta-data: ZT_UserMessage structure - */ - ZT_EVENT_USER_MESSAGE = 6 + /** + * VERB_USER_MESSAGE received + * + * These are generated when a VERB_USER_MESSAGE packet is received via + * ZeroTier VL1. This can be used for below-VL2 in-band application + * specific signaling over the ZeroTier protocol. + * + * It's up to you to ensure that you handle these in a way that does + * not introduce a remote security vulnerability into your app! If + * your USER_MESSAGE code has a buffer overflow or other vulnerability + * then your app will be vulnerable and this is not ZT's fault. :) + * + * Meta-data: ZT_UserMessage structure + */ + ZT_EVENT_USER_MESSAGE = 6 }; /** @@ -1106,104 +1088,100 @@ enum ZT_Event * Pointers to id and data might not remain valid after the event is * received. */ -typedef struct -{ - /** - * Identity of sender - */ - const ZT_Identity *id; +typedef struct { + /** + * Identity of sender + */ + const ZT_Identity* id; - /** - * User message type ID - */ - uint64_t typeId; + /** + * User message type ID + */ + uint64_t typeId; - /** - * User message data - */ - const void *data; + /** + * User message data + */ + const void* data; - /** - * Length of data in bytes - */ - unsigned int length; + /** + * Length of data in bytes + */ + unsigned int length; } ZT_UserMessage; /** * Current node status */ -typedef struct -{ - /** - * 40-bit ZeroTier address of this node - */ - uint64_t address; +typedef struct { + /** + * 40-bit ZeroTier address of this node + */ + uint64_t address; - /** - * Actual identity object for this node - */ - const ZT_Identity *identity; + /** + * Actual identity object for this node + */ + const ZT_Identity* identity; - /** - * Public identity in string-serialized form (safe to send to others) - * - * This pointer will remain valid as long as the node exists. - */ - const char *publicIdentity; + /** + * Public identity in string-serialized form (safe to send to others) + * + * This pointer will remain valid as long as the node exists. + */ + const char* publicIdentity; - /** - * Full identity including secret key in string-serialized form - * - * This pointer will remain valid as long as the node exists. - */ - const char *secretIdentity; + /** + * Full identity including secret key in string-serialized form + * + * This pointer will remain valid as long as the node exists. + */ + const char* secretIdentity; - /** - * True if some kind of connectivity appears available - */ - int online; + /** + * True if some kind of connectivity appears available + */ + int online; } ZT_NodeStatus; /** * Virtual network status codes */ -enum ZT_VirtualNetworkStatus -{ - /** - * Waiting for network configuration (also means revision == 0) - */ - ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, +enum ZT_VirtualNetworkStatus { + /** + * Waiting for network configuration (also means revision == 0) + */ + ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, - /** - * Configuration received and we are authorized - */ - ZT_NETWORK_STATUS_OK = 1, + /** + * Configuration received and we are authorized + */ + ZT_NETWORK_STATUS_OK = 1, - /** - * Netconf master told us 'nope' - */ - ZT_NETWORK_STATUS_ACCESS_DENIED = 2, + /** + * Netconf master told us 'nope' + */ + ZT_NETWORK_STATUS_ACCESS_DENIED = 2, - /** - * Netconf master exists, but this virtual network does not - */ - ZT_NETWORK_STATUS_NOT_FOUND = 3 + /** + * Netconf master exists, but this virtual network does not + */ + ZT_NETWORK_STATUS_NOT_FOUND = 3 }; /** * Virtual network type codes */ -enum ZT_VirtualNetworkType -{ - /** - * Private networks are authorized via membership credentials - */ - ZT_NETWORK_TYPE_PRIVATE = 0, +enum ZT_VirtualNetworkType { + /** + * Private networks are authorized via membership credentials + */ + ZT_NETWORK_TYPE_PRIVATE = 0, - /** - * Public networks have no access control -- they'll always be AUTHORIZED - */ - ZT_NETWORK_TYPE_PUBLIC = 1 + /** + * Public networks have no access control -- they'll always be AUTHORIZED + */ + ZT_NETWORK_TYPE_PUBLIC = 1 }; /** @@ -1215,85 +1193,84 @@ enum ZT_VirtualNetworkType * Each rule is composed of zero or more MATCHes followed by an ACTION. * An ACTION with no MATCHes is always taken. */ -enum ZT_VirtualNetworkRuleType -{ - /* 0 to 15 reserved for actions */ +enum ZT_VirtualNetworkRuleType { + /* 0 to 15 reserved for actions */ - /** - * Drop frame - */ - ZT_NETWORK_RULE_ACTION_DROP = 0, + /** + * Drop frame + */ + ZT_NETWORK_RULE_ACTION_DROP = 0, - /** - * Accept and pass frame - */ - ZT_NETWORK_RULE_ACTION_ACCEPT = 1, + /** + * Accept and pass frame + */ + ZT_NETWORK_RULE_ACTION_ACCEPT = 1, - /** - * Forward a copy of this frame to an observer (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_TEE = 2, + /** + * Forward a copy of this frame to an observer (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_TEE = 2, - /** - * Exactly like TEE but mandates ACKs from observer - */ - ZT_NETWORK_RULE_ACTION_WATCH = 3, + /** + * Exactly like TEE but mandates ACKs from observer + */ + ZT_NETWORK_RULE_ACTION_WATCH = 3, - /** - * Drop and redirect this frame to another node (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_REDIRECT = 4, + /** + * Drop and redirect this frame to another node (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_REDIRECT = 4, - /** - * Stop evaluating rule set (drops unless there are capabilities, etc.) - */ - ZT_NETWORK_RULE_ACTION_BREAK = 5, + /** + * Stop evaluating rule set (drops unless there are capabilities, etc.) + */ + ZT_NETWORK_RULE_ACTION_BREAK = 5, - /** - * Place a matching frame in the specified QoS bucket - */ - ZT_NETWORK_RULE_ACTION_PRIORITY = 6, + /** + * Place a matching frame in the specified QoS bucket + */ + ZT_NETWORK_RULE_ACTION_PRIORITY = 6, - /** - * Maximum ID for an ACTION, anything higher is a MATCH - */ - ZT_NETWORK_RULE_ACTION__MAX_ID = 15, + /** + * Maximum ID for an ACTION, anything higher is a MATCH + */ + ZT_NETWORK_RULE_ACTION__MAX_ID = 15, - // 16 to 63 reserved for match criteria + // 16 to 63 reserved for match criteria - ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, - ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, - ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, - ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, - ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, - ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, - ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, - ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, - ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, - ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, - ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, - ZT_NETWORK_RULE_MATCH_IP_TOS = 35, - ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, - ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, - ZT_NETWORK_RULE_MATCH_ICMP = 38, - ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, - ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, - ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, - ZT_NETWORK_RULE_MATCH_RANDOM = 43, - ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, - ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, - ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, - ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, - ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, + ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, + ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, + ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, + ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, + ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, + ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, + ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, + ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, + ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, + ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, + ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, + ZT_NETWORK_RULE_MATCH_IP_TOS = 35, + ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, + ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, + ZT_NETWORK_RULE_MATCH_ICMP = 38, + ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, + ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, + ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, + ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, + ZT_NETWORK_RULE_MATCH_RANDOM = 43, + ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, + ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, + ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, + ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, + ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, - /** - * Maximum ID allowed for a MATCH entry in the rules table - */ - ZT_NETWORK_RULE_MATCH__MAX_ID = 63 + /** + * Maximum ID allowed for a MATCH entry in the rules table + */ + ZT_NETWORK_RULE_MATCH__MAX_ID = 63 }; /** @@ -1307,375 +1284,359 @@ enum ZT_VirtualNetworkRuleType * This is designed to be a more memory-efficient way of storing rules than * a wide table, yet still fast and simple to access in code. */ -typedef struct -{ - /** - * Type and flags - * - * Bits are: NOTTTTTT - * - * N - If true, sense of match is inverted (no effect on actions) - * O - If true, result is ORed with previous instead of ANDed (no effect on actions) - * T - Rule or action type - * - * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. - */ - uint8_t t; +typedef struct { + /** + * Type and flags + * + * Bits are: NOTTTTTT + * + * N - If true, sense of match is inverted (no effect on actions) + * O - If true, result is ORed with previous instead of ANDed (no effect on actions) + * T - Rule or action type + * + * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. + */ + uint8_t t; - /** - * Union containing the value of this rule -- which field is used depends on 't' - */ - union - { - /** - * IPv6 address in big-endian / network byte order and netmask bits - */ - struct - { - uint8_t ip[16]; - uint8_t mask; - } ipv6; + /** + * Union containing the value of this rule -- which field is used depends on 't' + */ + union { + /** + * IPv6 address in big-endian / network byte order and netmask bits + */ + struct { + uint8_t ip[16]; + uint8_t mask; + } ipv6; - /** - * IPv4 address in big-endian / network byte order - */ - struct - { - uint32_t ip; - uint8_t mask; - } ipv4; + /** + * IPv4 address in big-endian / network byte order + */ + struct { + uint32_t ip; + uint8_t mask; + } ipv4; - /** - * Integer range match in packet payload - * - * This allows matching of ranges of integers up to 64 bits wide where - * the range is +/- INT32_MAX. It's packed this way so it fits in 16 - * bytes and doesn't enlarge the overall size of this union. - */ - struct - { - uint64_t start; /* integer range start */ - uint32_t end; /* end of integer range (relative to start, inclusive, 0 for equality w/start) */ - uint16_t idx; /* index in packet of integer */ - uint8_t format; /* bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) */ - } intRange; + /** + * Integer range match in packet payload + * + * This allows matching of ranges of integers up to 64 bits wide where + * the range is +/- INT32_MAX. It's packed this way so it fits in 16 + * bytes and doesn't enlarge the overall size of this union. + */ + struct { + uint64_t start; /* integer range start */ + uint32_t end; /* end of integer range (relative to start, inclusive, 0 for equality w/start) */ + uint16_t idx; /* index in packet of integer */ + uint8_t + format; /* bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) */ + } intRange; - /** - * Packet characteristic flags being matched - */ - uint64_t characteristics; + /** + * Packet characteristic flags being matched + */ + uint64_t characteristics; - /** - * IP port range -- start-end inclusive -- host byte order - */ - uint16_t port[2]; + /** + * IP port range -- start-end inclusive -- host byte order + */ + uint16_t port[2]; - /** - * 40-bit ZeroTier address (in least significant bits, host byte order) - */ - uint64_t zt; + /** + * 40-bit ZeroTier address (in least significant bits, host byte order) + */ + uint64_t zt; - /** - * 0 = never, UINT32_MAX = always - */ - uint32_t randomProbability; + /** + * 0 = never, UINT32_MAX = always + */ + uint32_t randomProbability; - /** - * 48-bit Ethernet MAC address in big-endian order - */ - uint8_t mac[6]; + /** + * 48-bit Ethernet MAC address in big-endian order + */ + uint8_t mac[6]; - /** - * VLAN ID in host byte order - */ - uint16_t vlanId; + /** + * VLAN ID in host byte order + */ + uint16_t vlanId; - /** - * VLAN PCP (least significant 3 bits) - */ - uint8_t vlanPcp; + /** + * VLAN PCP (least significant 3 bits) + */ + uint8_t vlanPcp; - /** - * VLAN DEI (single bit / boolean) - */ - uint8_t vlanDei; + /** + * VLAN DEI (single bit / boolean) + */ + uint8_t vlanDei; - /** - * Ethernet type in host byte order - */ - uint16_t etherType; + /** + * Ethernet type in host byte order + */ + uint16_t etherType; - /** - * IP protocol - */ - uint8_t ipProtocol; + /** + * IP protocol + */ + uint8_t ipProtocol; - /** - * IP type of service a.k.a. DSCP field - */ - struct - { - uint8_t mask; - uint8_t value[2]; - } ipTos; + /** + * IP type of service a.k.a. DSCP field + */ + struct { + uint8_t mask; + uint8_t value[2]; + } ipTos; - /** - * Ethernet packet size in host byte order (start-end, inclusive) - */ - uint16_t frameSize[2]; + /** + * Ethernet packet size in host byte order (start-end, inclusive) + */ + uint16_t frameSize[2]; - /** - * ICMP type and code - */ - struct - { - uint8_t type; /* ICMP type, always matched */ - uint8_t code; /* ICMP code if matched */ - uint8_t flags; /* flag 0x01 means also match code, otherwise only match type */ - } icmp; + /** + * ICMP type and code + */ + struct { + uint8_t type; /* ICMP type, always matched */ + uint8_t code; /* ICMP code if matched */ + uint8_t flags; /* flag 0x01 means also match code, otherwise only match type */ + } icmp; - /** - * For tag-related rules - */ - struct - { - uint32_t id; - uint32_t value; - } tag; + /** + * For tag-related rules + */ + struct { + uint32_t id; + uint32_t value; + } tag; - /** - * Destinations for TEE and REDIRECT - */ - struct - { - uint64_t address; - uint32_t flags; - uint16_t length; - } fwd; + /** + * Destinations for TEE and REDIRECT + */ + struct { + uint64_t address; + uint32_t flags; + uint16_t length; + } fwd; - /** - * Quality of Service (QoS) bucket we want a frame to be placed in - */ - uint8_t qosBucket; - } v; + /** + * Quality of Service (QoS) bucket we want a frame to be placed in + */ + uint8_t qosBucket; + } v; } ZT_VirtualNetworkRule; /** * A route to be pushed on a virtual network */ -typedef struct -{ - /** - * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default - */ - ZT_InetAddress target; +typedef struct { + /** + * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default + */ + ZT_InetAddress target; - /** - * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) - */ - ZT_InetAddress via; + /** + * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) + */ + ZT_InetAddress via; - /** - * Route flags - */ - uint16_t flags; + /** + * Route flags + */ + uint16_t flags; - /** - * Route metric - */ - uint16_t metric; + /** + * Route metric + */ + uint16_t metric; } ZT_VirtualNetworkRoute; /** * An Ethernet multicast group */ -typedef struct -{ - /** - * MAC address (least significant 48 bits) - */ - uint64_t mac; +typedef struct { + /** + * MAC address (least significant 48 bits) + */ + uint64_t mac; - /** - * Additional distinguishing information (usually zero) - */ - unsigned long adi; + /** + * Additional distinguishing information (usually zero) + */ + unsigned long adi; } ZT_MulticastGroup; /** * Virtual network configuration update type */ -enum ZT_VirtualNetworkConfigOperation -{ - /** - * Network is coming up (either for the first time or after service restart) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, +enum ZT_VirtualNetworkConfigOperation { + /** + * Network is coming up (either for the first time or after service restart) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, - /** - * Network configuration has been updated - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, + /** + * Network configuration has been updated + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, - /** - * Network is going down (not permanently) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, + /** + * Network is going down (not permanently) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, - /** - * Network is going down permanently (leave/delete) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 + /** + * Network is going down permanently (leave/delete) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; /** * Virtual network configuration */ -typedef struct -{ - /** - * 64-bit ZeroTier network ID - */ - uint64_t nwid; +typedef struct { + /** + * 64-bit ZeroTier network ID + */ + uint64_t nwid; - /** - * Ethernet MAC (48 bits) that should be assigned to port - */ - uint64_t mac; + /** + * Ethernet MAC (48 bits) that should be assigned to port + */ + uint64_t mac; - /** - * Network name (from network configuration master) - */ - char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; + /** + * Network name (from network configuration master) + */ + char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; - /** - * Network configuration request status - */ - enum ZT_VirtualNetworkStatus status; + /** + * Network configuration request status + */ + enum ZT_VirtualNetworkStatus status; - /** - * Network type - */ - enum ZT_VirtualNetworkType type; + /** + * Network type + */ + enum ZT_VirtualNetworkType type; - /** - * Maximum interface MTU - */ - unsigned int mtu; + /** + * Maximum interface MTU + */ + unsigned int mtu; - /** - * If nonzero, this port is allowed to bridge to other networks - * - * This is informational. If this is false (0), bridged packets will simply - * be dropped and bridging won't work. - */ - int bridge; + /** + * If nonzero, this port is allowed to bridge to other networks + * + * This is informational. If this is false (0), bridged packets will simply + * be dropped and bridging won't work. + */ + int bridge; - /** - * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic - */ - int broadcastEnabled; + /** + * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic + */ + int broadcastEnabled; - /** - * Revision number as reported by controller or 0 if still waiting for config - */ - unsigned long netconfRevision; + /** + * Revision number as reported by controller or 0 if still waiting for config + */ + unsigned long netconfRevision; - /** - * Number of assigned addresses - */ - unsigned int assignedAddressCount; + /** + * Number of assigned addresses + */ + unsigned int assignedAddressCount; - /** - * ZeroTier-assigned addresses (in sockaddr_storage structures) - * - * For IP, the port number of the sockaddr_XX structure contains the number - * of bits in the address netmask. Only the IP address and port are used. - * Other fields like interface number can be ignored. - * - * This is only used for ZeroTier-managed address assignments sent by the - * virtual network's configuration master. - */ - ZT_InetAddress assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + /** + * ZeroTier-assigned addresses (in sockaddr_storage structures) + * + * For IP, the port number of the sockaddr_XX structure contains the number + * of bits in the address netmask. Only the IP address and port are used. + * Other fields like interface number can be ignored. + * + * This is only used for ZeroTier-managed address assignments sent by the + * virtual network's configuration master. + */ + ZT_InetAddress assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; - /** - * Number of ZT-pushed routes - */ - unsigned int routeCount; + /** + * Number of ZT-pushed routes + */ + unsigned int routeCount; - /** - * Routes (excluding those implied by assigned addresses and their masks) - */ - ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; + /** + * Routes (excluding those implied by assigned addresses and their masks) + */ + ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; } ZT_VirtualNetworkConfig; /** * A list of networks */ -typedef struct -{ - void (*freeFunction)(const void *); +typedef struct { + void (*freeFunction)(const void*); - ZT_VirtualNetworkConfig *networks; - unsigned long networkCount; + ZT_VirtualNetworkConfig* networks; + unsigned long networkCount; } ZT_VirtualNetworkList; /** * Address where this node could be reached via an external interface */ -typedef struct -{ - /** - * IP and port as would be reachable by external nodes - */ - ZT_InetAddress address; +typedef struct { + /** + * IP and port as would be reachable by external nodes + */ + ZT_InetAddress address; - /** - * If nonzero this address is static and can be incorporated into this node's Locator - */ - int permanent; + /** + * If nonzero this address is static and can be incorporated into this node's Locator + */ + int permanent; } ZT_InterfaceAddress; /** * Variant type for storing possible path endpoints or peer contact points. */ -typedef struct -{ - /** - * Endpoint type, which determines what field in the union 'a' applies. - */ - enum ZT_EndpointType type; +typedef struct { + /** + * Endpoint type, which determines what field in the union 'a' applies. + */ + enum ZT_EndpointType type; - union - { - /** - * ZT_InetAddress, which is identically sized to sockaddr_storage. - * - * The ZT_InetAddress conversion macros can be used to get this in the - * form of a sockaddr, sockaddr_in, etc. - */ - ZT_InetAddress ia; + union { + /** + * ZT_InetAddress, which is identically sized to sockaddr_storage. + * + * The ZT_InetAddress conversion macros can be used to get this in the + * form of a sockaddr, sockaddr_in, etc. + */ + ZT_InetAddress ia; - /* When compiling the ZeroTier core, we want to explicitly define these - * in the union. Otherwise we don't because that would require these - * structures to be included. */ + /* When compiling the ZeroTier core, we want to explicitly define these + * in the union. Otherwise we don't because that would require these + * structures to be included. */ #ifdef ZT_CORE - struct sockaddr_storage ss; - struct sockaddr sa; - struct sockaddr_in sa_in; - struct sockaddr_in6 sa_in6; + struct sockaddr_storage ss; + struct sockaddr sa; + struct sockaddr_in sa_in; + struct sockaddr_in6 sa_in6; #endif - /** - * MAC address (least significant 48 bites) for ZT_ENDPOINT_TYPE_ETHERNET and other MAC addressed types - */ - uint64_t mac; + /** + * MAC address (least significant 48 bites) for ZT_ENDPOINT_TYPE_ETHERNET and other MAC addressed types + */ + uint64_t mac; - /** - * ZeroTier node address and identity fingerprint for ZT_ENDPOINT_TYPE_ZEROTIER - */ - ZT_Fingerprint fp; - } value; + /** + * ZeroTier node address and identity fingerprint for ZT_ENDPOINT_TYPE_ZEROTIER + */ + ZT_Fingerprint fp; + } value; } ZT_Endpoint; /** @@ -1689,193 +1650,189 @@ typedef void ZT_EndpointAttributes; /** * Network path to a peer */ -typedef struct -{ - /** - * Path endpoint - */ - ZT_Endpoint endpoint; +typedef struct { + /** + * Path endpoint + */ + ZT_Endpoint endpoint; - /** - * Time of last send in milliseconds or 0 for never - */ - int64_t lastSend; + /** + * Time of last send in milliseconds or 0 for never + */ + int64_t lastSend; - /** - * Time of last receive in milliseconds or 0 for never - */ - int64_t lastReceive; + /** + * Time of last receive in milliseconds or 0 for never + */ + int64_t lastReceive; - /** - * Is path alive? - */ - int alive; + /** + * Is path alive? + */ + int alive; - /** - * Is path preferred? - */ - int preferred; + /** + * Is path preferred? + */ + int preferred; } ZT_Path; /** * Peer information */ -typedef struct -{ - /** - * ZeroTier address (40 bits) - */ - uint64_t address; +typedef struct { + /** + * ZeroTier address (40 bits) + */ + uint64_t address; - /** - * Peer identity - */ - const ZT_Identity *identity; + /** + * Peer identity + */ + const ZT_Identity* identity; - /** - * SHA-384 of identity public key(s) - */ - const ZT_Fingerprint *fingerprint; + /** + * SHA-384 of identity public key(s) + */ + const ZT_Fingerprint* fingerprint; - /** - * Remote major version or -1 if not known - */ - int versionMajor; + /** + * Remote major version or -1 if not known + */ + int versionMajor; - /** - * Remote minor version or -1 if not known - */ - int versionMinor; + /** + * Remote minor version or -1 if not known + */ + int versionMinor; - /** - * Remote revision or -1 if not known - */ - int versionRev; + /** + * Remote revision or -1 if not known + */ + int versionRev; - /** - * Remote protocol version or -1 if not known - */ - int versionProto; + /** + * Remote protocol version or -1 if not known + */ + int versionProto; - /** - * Last measured latency in milliseconds or -1 if unknown - */ - int latency; + /** + * Last measured latency in milliseconds or -1 if unknown + */ + int latency; - /** - * If non-zero this peer is a root - */ - int root; + /** + * If non-zero this peer is a root + */ + int root; - /** - * Network IDs for networks (array size: networkCount) - */ - uint64_t *networks; + /** + * Network IDs for networks (array size: networkCount) + */ + uint64_t* networks; - /** - * Number of networks in which this peer is authenticated - */ - unsigned int networkCount; + /** + * Number of networks in which this peer is authenticated + */ + unsigned int networkCount; - /** - * Known network paths to peer (array size: pathCount). - * - * These are direct paths only. Endpoints can also describe indirect paths, - * but those would not appear here. Right now those can only be relaying via - * a root. - */ - ZT_Path *paths; + /** + * Known network paths to peer (array size: pathCount). + * + * These are direct paths only. Endpoints can also describe indirect paths, + * but those would not appear here. Right now those can only be relaying via + * a root. + */ + ZT_Path* paths; - /** - * Number of paths (size of paths[]) - */ - unsigned int pathCount; + /** + * Number of paths (size of paths[]) + */ + unsigned int pathCount; - /** - * Size of locator in bytes or 0 if none - */ - unsigned int locatorSize; + /** + * Size of locator in bytes or 0 if none + */ + unsigned int locatorSize; - /** - * Serialized locator or NULL if none - */ - const void *locator; + /** + * Serialized locator or NULL if none + */ + const void* locator; } ZT_Peer; /** * List of peers */ -typedef struct -{ - void (*freeFunction)(const void *); +typedef struct { + void (*freeFunction)(const void*); - ZT_Peer *peers; - unsigned long peerCount; + ZT_Peer* peers; + unsigned long peerCount; } ZT_PeerList; /** * ZeroTier core state objects */ -enum ZT_StateObjectType -{ - /** - * Null object -- ignored - */ - ZT_STATE_OBJECT_NULL = 0, +enum ZT_StateObjectType { + /** + * Null object -- ignored + */ + ZT_STATE_OBJECT_NULL = 0, - /** - * Public address and public key - * - * Object ID: (none) - * Canonical path: /identity.public - * Persistence: required - */ - ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, + /** + * Public address and public key + * + * Object ID: (none) + * Canonical path: /identity.public + * Persistence: required + */ + ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, - /** - * Full identity with secret key - * - * Object ID: (none) - * Canonical path: /identity.secret - * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix - */ - ZT_STATE_OBJECT_IDENTITY_SECRET = 2, + /** + * Full identity with secret key + * + * Object ID: (none) + * Canonical path: /identity.secret + * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix + */ + ZT_STATE_OBJECT_IDENTITY_SECRET = 2, - /** - * This node's locator - * - * Object ID: (none) - * Canonical path: /locator - * Persistence: optional - */ - ZT_STATE_OBJECT_LOCATOR = 3, + /** + * This node's locator + * + * Object ID: (none) + * Canonical path: /locator + * Persistence: optional + */ + ZT_STATE_OBJECT_LOCATOR = 3, - /** - * Peer and related state - * - * Object ID: [1]address (40 bits, in least significant 64 bits) - * Canonical path: /peers.d/ (10-digit address) - * Persistence: optional, can be cleared at any time - */ - ZT_STATE_OBJECT_PEER = 5, + /** + * Peer and related state + * + * Object ID: [1]address (40 bits, in least significant 64 bits) + * Canonical path: /peers.d/ (10-digit address) + * Persistence: optional, can be cleared at any time + */ + ZT_STATE_OBJECT_PEER = 5, - /** - * Network configuration - * - * Object ID: [1]id (64-bit network ID) - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist - */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 6, + /** + * Network configuration + * + * Object ID: [1]id (64-bit network ID) + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist + */ + ZT_STATE_OBJECT_NETWORK_CONFIG = 6, - /** - * List of certificates, their local trust, and locally added roots - * - * Object ID: (none) - * Canonical path: /truststore - * Persistence: required if root settings should persist - */ - ZT_STATE_OBJECT_TRUST_STORE = 7 + /** + * List of certificates, their local trust, and locally added roots + * + * Object ID: (none) + * Canonical path: /truststore + * Persistence: required if root settings should persist + */ + ZT_STATE_OBJECT_TRUST_STORE = 7 }; /** @@ -1918,13 +1875,13 @@ typedef void ZT_Node; * driven environments. */ typedef void (*ZT_VirtualNetworkConfigFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - enum ZT_VirtualNetworkConfigOperation, /* Config operation */ - const ZT_VirtualNetworkConfig *); /* Network configuration */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* Network ID */ + void**, /* Modifiable network user PTR */ + enum ZT_VirtualNetworkConfigOperation, /* Config operation */ + const ZT_VirtualNetworkConfig*); /* Network configuration */ /** * Function to send a frame out to a virtual network port @@ -1934,17 +1891,17 @@ typedef void (*ZT_VirtualNetworkConfigFunction)( * (9) frame length. */ typedef void (*ZT_VirtualNetworkFrameFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - uint64_t, /* Source MAC */ - uint64_t, /* Destination MAC */ - unsigned int, /* Ethernet type */ - unsigned int, /* VLAN ID (0 for none) */ - const void *, /* Frame data */ - unsigned int); /* Frame length */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* Network ID */ + void**, /* Modifiable network user PTR */ + uint64_t, /* Source MAC */ + uint64_t, /* Destination MAC */ + unsigned int, /* Ethernet type */ + unsigned int, /* VLAN ID (0 for none) */ + const void*, /* Frame data */ + unsigned int); /* Frame length */ /** * Callback for events @@ -1956,12 +1913,12 @@ typedef void (*ZT_VirtualNetworkFrameFunction)( * in the definition of ZT_Event. */ typedef void (*ZT_EventCallback)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_Event, /* Event type */ - const void *, /* Event payload (if applicable) */ - unsigned int); /* Size of event payload */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_Event, /* Event type */ + const void*, /* Event payload (if applicable) */ + unsigned int); /* Size of event payload */ /** * Callback for storing and/or publishing state information @@ -1973,14 +1930,14 @@ typedef void (*ZT_EventCallback)( * deleted. */ typedef void (*ZT_StatePutFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t *, /* State object ID (if applicable) */ - unsigned int, /* Length of state object ID in quads */ - const void *, /* State object data */ - int); /* Length of data or -1 to delete */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t*, /* State object ID (if applicable) */ + unsigned int, /* Length of state object ID in quads */ + const void*, /* State object data */ + int); /* Length of data or -1 to delete */ /** * Callback for retrieving stored state information @@ -1992,14 +1949,14 @@ typedef void (*ZT_StatePutFunction)( * with it. This is very often just a pointer to free(). */ typedef int (*ZT_StateGetFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t *, /* State object ID (if applicable) */ - unsigned int, /* Length of object ID in quads */ - void **, /* Result parameter: data */ - void (**)(void *)); /* Result parameter: data free function */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t*, /* State object ID (if applicable) */ + unsigned int, /* Length of object ID in quads */ + void**, /* Result parameter: data */ + void (**)(void*)); /* Result parameter: data free function */ /** * Function to send a ZeroTier packet out over the physical wire (L2/L3) @@ -2017,14 +1974,14 @@ typedef int (*ZT_StateGetFunction)( * delivery. It only means that the packet appears to have been sent. */ typedef int (*ZT_WirePacketSendFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - int64_t, /* Local socket */ - const ZT_InetAddress *, /* Remote address */ - const void *, /* Packet data */ - unsigned int, /* Packet length */ - unsigned int); /* TTL or 0 to use default */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + int64_t, /* Local socket */ + const ZT_InetAddress*, /* Remote address */ + const void*, /* Packet data */ + unsigned int, /* Packet length */ + unsigned int); /* TTL or 0 to use default */ /** * Function to check whether a path should be used for ZeroTier traffic @@ -2049,13 +2006,13 @@ typedef int (*ZT_WirePacketSendFunction)( * interface (recursion). */ typedef int (*ZT_PathCheckFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address */ - const ZT_Identity *, /* Full identity of node */ - int64_t, /* Local socket or -1 if unknown */ - const ZT_InetAddress *); /* Remote address */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* ZeroTier address */ + const ZT_Identity*, /* Full identity of node */ + int64_t, /* Local socket or -1 if unknown */ + const ZT_InetAddress*); /* Remote address */ /** * Function to get physical addresses for ZeroTier peers @@ -2074,60 +2031,59 @@ typedef int (*ZT_PathCheckFunction)( * with an address. */ typedef int (*ZT_PathLookupFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address (40 bits) */ - const ZT_Identity *, /* Full identity of node */ - int, /* Desired ss_family or -1 for any */ - ZT_InetAddress *); /* Result buffer */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* ZeroTier address (40 bits) */ + const ZT_Identity*, /* Full identity of node */ + int, /* Desired ss_family or -1 for any */ + ZT_InetAddress*); /* Result buffer */ /* ---------------------------------------------------------------------------------------------------------------- */ /** * Structure for configuring ZeroTier core callback functions */ -struct ZT_Node_Callbacks -{ - /** - * REQUIRED: Function to store and/or replicate state objects - */ - ZT_StatePutFunction statePutFunction; +struct ZT_Node_Callbacks { + /** + * REQUIRED: Function to store and/or replicate state objects + */ + ZT_StatePutFunction statePutFunction; - /** - * REQUIRED: Function to retrieve state objects from an object store - */ - ZT_StateGetFunction stateGetFunction; + /** + * REQUIRED: Function to retrieve state objects from an object store + */ + ZT_StateGetFunction stateGetFunction; - /** - * REQUIRED: Function to send packets over the physical wire - */ - ZT_WirePacketSendFunction wirePacketSendFunction; + /** + * REQUIRED: Function to send packets over the physical wire + */ + ZT_WirePacketSendFunction wirePacketSendFunction; - /** - * REQUIRED: Function to inject frames into a virtual network's TAP - */ - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; + /** + * REQUIRED: Function to inject frames into a virtual network's TAP + */ + ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; - /** - * REQUIRED: Function to be called when virtual networks are configured or changed - */ - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; + /** + * REQUIRED: Function to be called when virtual networks are configured or changed + */ + ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; - /** - * REQUIRED: Function to be called to notify external code of important events - */ - ZT_EventCallback eventCallback; + /** + * REQUIRED: Function to be called to notify external code of important events + */ + ZT_EventCallback eventCallback; - /** - * OPTIONAL: Function to check whether a given physical path should be used for ZeroTier traffic - */ - ZT_PathCheckFunction pathCheckFunction; + /** + * OPTIONAL: Function to check whether a given physical path should be used for ZeroTier traffic + */ + ZT_PathCheckFunction pathCheckFunction; - /** - * RECOMMENDED: Function to look up paths to ZeroTier nodes - */ - ZT_PathLookupFunction pathLookupFunction; + /** + * RECOMMENDED: Function to look up paths to ZeroTier nodes + */ + ZT_PathLookupFunction pathLookupFunction; }; /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2142,14 +2098,14 @@ struct ZT_Node_Callbacks * * @return Pointer to I/O buffer */ -ZT_SDK_API void *ZT_getBuffer(); +ZT_SDK_API void* ZT_getBuffer(); /** * Free an unused buffer obtained via getBuffer * * @param b Buffer to free */ -ZT_SDK_API void ZT_freeBuffer(void *b); +ZT_SDK_API void ZT_freeBuffer(void* b); /** * Free a query result buffer @@ -2159,7 +2115,7 @@ ZT_SDK_API void ZT_freeBuffer(void *b); * * @param qr Query result buffer */ -ZT_SDK_API void ZT_freeQueryResult(const void *qr); +ZT_SDK_API void ZT_freeQueryResult(const void* qr); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2177,12 +2133,12 @@ ZT_SDK_API void ZT_freeQueryResult(const void *qr); * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - int64_t clock, - int64_t ticks, - void *tptr, - void *uptr, - const struct ZT_Node_Callbacks *callbacks); + ZT_Node** node, + int64_t clock, + int64_t ticks, + void* tptr, + void* uptr, + const struct ZT_Node_Callbacks* callbacks); /** * Delete a node and free all resources it consumes @@ -2190,11 +2146,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_new( * If you are using multiple threads, all other threads must be shut down * first. This can crash if processXXX() methods are in progress. */ -ZT_SDK_API void ZT_Node_delete( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr); +ZT_SDK_API void ZT_Node_delete(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr); /** * Process a packet received from the physical wire @@ -2208,16 +2160,16 @@ ZT_SDK_API void ZT_Node_delete( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - int64_t localSocket, - const ZT_InetAddress *remoteAddress, - const void *packetData, - unsigned int packetLength, - int isZtBuffer, - volatile int64_t *nextBackgroundTaskDeadline); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + int64_t localSocket, + const ZT_InetAddress* remoteAddress, + const void* packetData, + unsigned int packetLength, + int isZtBuffer, + volatile int64_t* nextBackgroundTaskDeadline); /** * Process a frame from a virtual network port (tap) @@ -2234,19 +2186,19 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - int isZtBuffer, - volatile int64_t *nextBackgroundTaskDeadline); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + int isZtBuffer, + volatile int64_t* nextBackgroundTaskDeadline); /** * Perform periodic background operations @@ -2256,11 +2208,11 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - volatile int64_t *nextBackgroundTaskDeadline); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + volatile int64_t* nextBackgroundTaskDeadline); /** * Join a network @@ -2276,13 +2228,13 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_join( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - void *uptr, - uint64_t nwid, - const ZT_Fingerprint *controllerFingerprint); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + void* uptr, + uint64_t nwid, + const ZT_Fingerprint* controllerFingerprint); /** * Leave a network @@ -2296,13 +2248,8 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_join( * * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_leave( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - void **uptr, - uint64_t nwid); +ZT_SDK_API enum ZT_ResultCode +ZT_Node_leave(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, void** uptr, uint64_t nwid); /** * Subscribe to an Ethernet multicast group @@ -2329,13 +2276,13 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_leave( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t multicastGroup, + unsigned long multicastAdi); /** * Unsubscribe from an Ethernet multicast group (or all groups) @@ -2351,21 +2298,20 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid, - uint64_t multicastGroup, - unsigned long multicastAdi); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t nwid, + uint64_t multicastGroup, + unsigned long multicastAdi); /** * Get this node's 40-bit ZeroTier address * * @return ZeroTier address (least significant 40 bits of 64-bit int) */ -ZT_SDK_API uint64_t ZT_Node_address( - ZT_Node *node); +ZT_SDK_API uint64_t ZT_Node_address(ZT_Node* node); /** * Get this node's identity @@ -2375,20 +2321,14 @@ ZT_SDK_API uint64_t ZT_Node_address( * * @return Identity */ -ZT_SDK_API const ZT_Identity *ZT_Node_identity( - ZT_Node *node); +ZT_SDK_API const ZT_Identity* ZT_Node_identity(ZT_Node* node); /** * Get the status of this node * * @param status Buffer to fill with current node status */ -ZT_SDK_API void ZT_Node_status( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - ZT_NodeStatus *status); +ZT_SDK_API void ZT_Node_status(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, ZT_NodeStatus* status); /** * Get a list of known peer nodes @@ -2398,11 +2338,7 @@ ZT_SDK_API void ZT_Node_status( * * @return List of known peers or NULL on failure */ -ZT_SDK_API ZT_PeerList *ZT_Node_peers( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr); +ZT_SDK_API ZT_PeerList* ZT_Node_peers(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr); /** * Get the status of a virtual network @@ -2413,12 +2349,8 @@ ZT_SDK_API ZT_PeerList *ZT_Node_peers( * @param nwid 64-bit network ID * @return Network configuration or NULL if we are not a member of this network */ -ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t nwid); +ZT_SDK_API ZT_VirtualNetworkConfig* +ZT_Node_networkConfig(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, uint64_t nwid); /** * Enumerate and get status of all networks @@ -2426,8 +2358,7 @@ ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig( * @param node Node instance * @return List of networks or NULL on failure */ -ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks( - ZT_Node *node); +ZT_SDK_API ZT_VirtualNetworkList* ZT_Node_networks(ZT_Node* node); /** * Set the network-associated user-defined pointer for a given network @@ -2438,10 +2369,7 @@ ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks( * @param nwid Network ID * @param ptr New network-associated pointer */ -ZT_SDK_API void ZT_Node_setNetworkUserPtr( - ZT_Node *node, - uint64_t nwid, - void *ptr); +ZT_SDK_API void ZT_Node_setNetworkUserPtr(ZT_Node* node, uint64_t nwid, void* ptr); /** * Set external interface addresses where this node could be reached @@ -2451,12 +2379,12 @@ ZT_SDK_API void ZT_Node_setNetworkUserPtr( * @param addrCount Number of items in addrs[] */ ZT_SDK_API void ZT_Node_setInterfaceAddresses( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - const ZT_InterfaceAddress *addrs, - unsigned int addrCount); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + const ZT_InterfaceAddress* addrs, + unsigned int addrCount); /** * Add a certificate to this node's certificate store @@ -2471,14 +2399,14 @@ ZT_SDK_API void ZT_Node_setInterfaceAddresses( * @return Certificate error or ZT_CERTIFICATE_ERROR_NONE on success */ ZT_SDK_API enum ZT_CertificateError ZT_Node_addCertificate( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - unsigned int localTrust, - const ZT_Certificate *cert, - const void *certData, - unsigned int certSize); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + unsigned int localTrust, + const ZT_Certificate* cert, + const void* certData, + unsigned int certSize); /** * Delete a certificate from this node's certificate store @@ -2491,12 +2419,8 @@ ZT_SDK_API enum ZT_CertificateError ZT_Node_addCertificate( * @param serialNo 48-byte / 384-bit serial number of certificate to delete * @return OK (0) or error code */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_deleteCertificate( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - const void *serialNo); +ZT_SDK_API enum ZT_ResultCode +ZT_Node_deleteCertificate(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr, const void* serialNo); /** * List certificates installed in this node's trust store @@ -2504,11 +2428,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_deleteCertificate( * @param node Node instance * @return List of certificates or NULL on error */ -ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr); +ZT_SDK_API ZT_CertificateList* ZT_Node_listCertificates(ZT_Node* node, int64_t clock, int64_t ticks, void* tptr); /** * Send a VERB_USER_MESSAGE to another ZeroTier node @@ -2525,14 +2445,14 @@ ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates( * @return Boolean: non-zero on success, zero on failure */ ZT_SDK_API int ZT_Node_sendUserMessage( - ZT_Node *node, - int64_t clock, - int64_t ticks, - void *tptr, - uint64_t dest, - uint64_t typeId, - const void *data, - unsigned int len); + ZT_Node* node, + int64_t clock, + int64_t ticks, + void* tptr, + uint64_t dest, + uint64_t typeId, + const void* data, + unsigned int len); /** * Set a network controller instance for this node @@ -2549,9 +2469,7 @@ ZT_SDK_API int ZT_Node_sendUserMessage( * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API void ZT_Node_setController( - ZT_Node *node, - void *networkConfigMasterInstance); +ZT_SDK_API void ZT_Node_setController(ZT_Node* node, void* networkConfigMasterInstance); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2565,7 +2483,7 @@ ZT_SDK_API void ZT_Node_setController( * @param type Type of identity to generate * @return New identity or NULL on error */ -ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type); +ZT_SDK_API ZT_Identity* ZT_Identity_new(enum ZT_IdentityType type); /** * Make a copy of an identity @@ -2573,7 +2491,7 @@ ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type); * @param id Identity to copy * @return Copy, must be freed with ZT_Identity_delete. */ -ZT_SDK_API ZT_Identity *ZT_Identity_clone(const ZT_Identity *id); +ZT_SDK_API ZT_Identity* ZT_Identity_clone(const ZT_Identity* id); /** * Create a new identity object from a string-serialized identity @@ -2581,7 +2499,7 @@ ZT_SDK_API ZT_Identity *ZT_Identity_clone(const ZT_Identity *id); * @param idStr Identity in string format * @return Identity object or NULL if the supplied identity string was not valid */ -ZT_SDK_API ZT_Identity *ZT_Identity_fromString(const char *idStr); +ZT_SDK_API ZT_Identity* ZT_Identity_fromString(const char* idStr); /** * Validate this identity @@ -2590,7 +2508,7 @@ ZT_SDK_API ZT_Identity *ZT_Identity_fromString(const char *idStr); * * @return Non-zero if identity is valid */ -ZT_SDK_API int ZT_Identity_validate(const ZT_Identity *id); +ZT_SDK_API int ZT_Identity_validate(const ZT_Identity* id); /** * Sign a data object with this identity @@ -2605,11 +2523,11 @@ ZT_SDK_API int ZT_Identity_validate(const ZT_Identity *id); * @return Length of signature in bytes or 0 on failure. */ ZT_SDK_API unsigned int ZT_Identity_sign( - const ZT_Identity *id, - const void *data, - unsigned int len, - void *signature, - unsigned int signatureBufferLength); + const ZT_Identity* id, + const void* data, + unsigned int len, + void* signature, + unsigned int signatureBufferLength); /** * Verify a signature @@ -2622,11 +2540,11 @@ ZT_SDK_API unsigned int ZT_Identity_sign( * @return Non-zero if signature is valid */ ZT_SDK_API int ZT_Identity_verify( - const ZT_Identity *id, - const void *data, - unsigned int len, - const void *signature, - unsigned int sigLen); + const ZT_Identity* id, + const void* data, + unsigned int len, + const void* signature, + unsigned int sigLen); /** * Get identity type @@ -2634,7 +2552,7 @@ ZT_SDK_API int ZT_Identity_verify( * @param id Identity to query * @return Identity type code */ -ZT_SDK_API enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id); +ZT_SDK_API enum ZT_IdentityType ZT_Identity_type(const ZT_Identity* id); /** * Convert an identity to its string representation @@ -2645,11 +2563,7 @@ ZT_SDK_API enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id); * @param includePrivate If true include the private key if present * @return Pointer to buf or NULL on overflow or other error */ -ZT_SDK_API char *ZT_Identity_toString( - const ZT_Identity *id, - char *buf, - int capacity, - int includePrivate); +ZT_SDK_API char* ZT_Identity_toString(const ZT_Identity* id, char* buf, int capacity, int includePrivate); /** * Check whether this identity object also holds a private key @@ -2657,7 +2571,7 @@ ZT_SDK_API char *ZT_Identity_toString( * @param id Identity to query * @return Non-zero if a private key is held */ -ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity *id); +ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity* id); /** * Get the ZeroTier address associated with this identity @@ -2665,7 +2579,7 @@ ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity *id); * @param id Identity to query * @return ZeroTier address (only least significant 40 bits are meaningful, rest will be 0) */ -ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id); +ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity* id); /** * Get this identity's full fingerprint @@ -2673,7 +2587,7 @@ ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id); * @param id Identity to query * @return Pointer to fingerprint (remains valid as long as identity itself is valid) */ -ZT_SDK_API const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id); +ZT_SDK_API const ZT_Fingerprint* ZT_Identity_fingerprint(const ZT_Identity* id); /** * Compare two identities @@ -2682,7 +2596,7 @@ ZT_SDK_API const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id); * @param b Second identity * @return -1, 0, or 1 if a is less than, equal to, or greater than b */ -ZT_SDK_API int ZT_Identity_compare(const ZT_Identity *a, const ZT_Identity *b); +ZT_SDK_API int ZT_Identity_compare(const ZT_Identity* a, const ZT_Identity* b); /** * Delete an identity and free associated memory @@ -2692,7 +2606,7 @@ ZT_SDK_API int ZT_Identity_compare(const ZT_Identity *a, const ZT_Identity *b); * * @param id Identity to delete */ -ZT_SDK_API void ZT_Identity_delete(const ZT_Identity *id); +ZT_SDK_API void ZT_Identity_delete(const ZT_Identity* id); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2704,10 +2618,7 @@ ZT_SDK_API void ZT_Identity_delete(const ZT_Identity *id); * @param capacity Capacity of buffer * @return String or NULL on error */ -ZT_SDK_API char *ZT_Endpoint_toString( - const ZT_Endpoint *ep, - char *buf, - int capacity); +ZT_SDK_API char* ZT_Endpoint_toString(const ZT_Endpoint* ep, char* buf, int capacity); /** * Parse an endpoint as a string @@ -2720,9 +2631,7 @@ ZT_SDK_API char *ZT_Endpoint_toString( * @param str String representation of endpoint * @return OK (0) or error code */ -ZT_SDK_API int ZT_Endpoint_fromString( - ZT_Endpoint *ep, - const char *str); +ZT_SDK_API int ZT_Endpoint_fromString(ZT_Endpoint* ep, const char* str); /** * Decode a binary serialized endpoint @@ -2732,10 +2641,7 @@ ZT_SDK_API int ZT_Endpoint_fromString( * @param len Length of bytes * @return OK (0) or error code */ -ZT_SDK_API int ZT_Endpoint_fromBytes( - ZT_Endpoint *ep, - const void *bytes, - unsigned int len); +ZT_SDK_API int ZT_Endpoint_fromBytes(ZT_Endpoint* ep, const void* bytes, unsigned int len); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2752,12 +2658,12 @@ ZT_SDK_API int ZT_Endpoint_fromBytes( * @param signer Identity to sign locator (must include private key) * @return Locator or NULL on error (too many endpoints or identity does not have private key) */ -ZT_SDK_API ZT_Locator *ZT_Locator_create( - int64_t rev, - const ZT_Endpoint *endpoints, - const ZT_EndpointAttributes *endpointAttributes, - unsigned int endpointCount, - const ZT_Identity *signer); +ZT_SDK_API ZT_Locator* ZT_Locator_create( + int64_t rev, + const ZT_Endpoint* endpoints, + const ZT_EndpointAttributes* endpointAttributes, + unsigned int endpointCount, + const ZT_Identity* signer); /** * Decode a serialized locator @@ -2766,9 +2672,7 @@ ZT_SDK_API ZT_Locator *ZT_Locator_create( * @param len Length of data * @return Locator or NULL if data is not valid */ -ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal( - const void *data, - unsigned int len); +ZT_SDK_API ZT_Locator* ZT_Locator_unmarshal(const void* data, unsigned int len); /** * Decode a locator from string format @@ -2776,7 +2680,7 @@ ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal( * @param str String format locator * @return Locator or NULL if string is not valid */ -ZT_SDK_API ZT_Locator *ZT_Locator_fromString(const char *str); +ZT_SDK_API ZT_Locator* ZT_Locator_fromString(const char* str); /** * Serialize this locator into a buffer @@ -2786,10 +2690,7 @@ ZT_SDK_API ZT_Locator *ZT_Locator_fromString(const char *str); * @param bufSize Size of buffer in bytes (needs to be at least 2048 bytes in size) * @return Number of bytes stored to buf or -1 on error such as buffer too small */ -ZT_SDK_API int ZT_Locator_marshal( - const ZT_Locator *loc, - void *buf, - unsigned int bufSize); +ZT_SDK_API int ZT_Locator_marshal(const ZT_Locator* loc, void* buf, unsigned int bufSize); /** * Get this locator in string format @@ -2799,10 +2700,7 @@ ZT_SDK_API int ZT_Locator_marshal( * @param capacity Capacity of buffer in bytes (recommended size: 4096) * @return Pointer to buffer or NULL if an error occurs */ -ZT_SDK_API char *ZT_Locator_toString( - const ZT_Locator *loc, - char *buf, - int capacity); +ZT_SDK_API char* ZT_Locator_toString(const ZT_Locator* loc, char* buf, int capacity); /** * Get a locator's revision @@ -2810,7 +2708,7 @@ ZT_SDK_API char *ZT_Locator_toString( * @param loc Locator to query * @return Locator revision */ -ZT_SDK_API int64_t ZT_Locator_revision(const ZT_Locator *loc); +ZT_SDK_API int64_t ZT_Locator_revision(const ZT_Locator* loc); /** * Get a locator's signer @@ -2818,7 +2716,7 @@ ZT_SDK_API int64_t ZT_Locator_revision(const ZT_Locator *loc); * @param loc Locator to query * @return 40-bit ZeroTier address of signer */ -ZT_SDK_API uint64_t ZT_Locator_signer(const ZT_Locator *loc); +ZT_SDK_API uint64_t ZT_Locator_signer(const ZT_Locator* loc); /** * Compare two locators @@ -2827,7 +2725,7 @@ ZT_SDK_API uint64_t ZT_Locator_signer(const ZT_Locator *loc); * @param b Second locator * @return Non-zero if a equals b */ -ZT_SDK_API int ZT_Locator_equals(const ZT_Locator *a, const ZT_Locator *b); +ZT_SDK_API int ZT_Locator_equals(const ZT_Locator* a, const ZT_Locator* b); /** * Get the number of endpoints in this locator @@ -2835,7 +2733,7 @@ ZT_SDK_API int ZT_Locator_equals(const ZT_Locator *a, const ZT_Locator *b); * @param loc Locator to query * @return Number of endpoints */ -ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc); +ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator* loc); /** * Get a pointer to an endpoint in a locator @@ -2845,9 +2743,7 @@ ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc); * @param ep Endpoint number from 0 to 1 - endpointCount() * @return Endpoint or NULL if out of bounds */ -ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint( - const ZT_Locator *loc, - unsigned int ep); +ZT_SDK_API const ZT_Endpoint* ZT_Locator_endpoint(const ZT_Locator* loc, unsigned int ep); /** * Verify this locator's signature @@ -2855,16 +2751,14 @@ ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint( * @param signer Signing identity * @return Non-zero if locator is valid */ -ZT_SDK_API int ZT_Locator_verify( - const ZT_Locator *loc, - const ZT_Identity *signer); +ZT_SDK_API int ZT_Locator_verify(const ZT_Locator* loc, const ZT_Identity* signer); /** * Delete a locator * * @param loc Locator to delete */ -ZT_SDK_API void ZT_Locator_delete(const ZT_Locator *loc); +ZT_SDK_API void ZT_Locator_delete(const ZT_Locator* loc); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2876,11 +2770,7 @@ ZT_SDK_API void ZT_Locator_delete(const ZT_Locator *loc); * @param revision Result: revision * @param build Result: build number */ -ZT_SDK_API void ZT_version( - int *major, - int *minor, - int *revision, - int *build); +ZT_SDK_API void ZT_version(int* major, int* minor, int* revision, int* build); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2898,11 +2788,11 @@ ZT_SDK_API void ZT_version( * @return OK (0) or error */ ZT_SDK_API int ZT_Certificate_newKeyPair( - enum ZT_CertificatePublicKeyAlgorithm type, - uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], - int *const publicKeySize, - uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], - int *const privateKeySize); + enum ZT_CertificatePublicKeyAlgorithm type, + uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], + int* const publicKeySize, + uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], + int* const privateKeySize); /** * Create a new certificate signing request (CSR) @@ -2923,13 +2813,13 @@ ZT_SDK_API int ZT_Certificate_newKeyPair( * @return OK (0) or error */ ZT_SDK_API int ZT_Certificate_newCSR( - const ZT_Certificate_Subject *subject, - const void *certificatePublicKey, - int certificatePublicKeySize, - const void *uniqueIdPrivateKey, - int uniqueIdPrivateKeySize, - void *csr, - int *csrSize); + const ZT_Certificate_Subject* subject, + const void* certificatePublicKey, + int certificatePublicKeySize, + const void* uniqueIdPrivateKey, + int uniqueIdPrivateKeySize, + void* csr, + int* csrSize); /** * Sign a CSR to generate a complete certificate. @@ -2946,11 +2836,11 @@ ZT_SDK_API int ZT_Certificate_newCSR( * @param issuerPrivateKeySize Size of private key in bytes * @return Signed certificate or NULL on error */ -ZT_SDK_API ZT_Certificate *ZT_Certificate_sign( - const ZT_Certificate *cert, - const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], - const void *issuerPrivateKey, - int issuerPrivateKeySize); +ZT_SDK_API ZT_Certificate* ZT_Certificate_sign( + const ZT_Certificate* cert, + const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], + const void* issuerPrivateKey, + int issuerPrivateKeySize); /** * Decode a certificate or CSR @@ -2967,11 +2857,8 @@ ZT_SDK_API ZT_Certificate *ZT_Certificate_sign( * @param verify If non-zero, verify signatures and structure * @return Certificate error, if any */ -ZT_SDK_API enum ZT_CertificateError ZT_Certificate_decode( - const ZT_Certificate **decodedCert, - const void *cert, - int certSize, - int verify); +ZT_SDK_API enum ZT_CertificateError +ZT_Certificate_decode(const ZT_Certificate** decodedCert, const void* cert, int certSize, int verify); /** * Encode a certificate @@ -2981,10 +2868,7 @@ ZT_SDK_API enum ZT_CertificateError ZT_Certificate_decode( * @param encodedSize Value/result: size of certificate encoding buffer * @return OK (0) or error */ -ZT_SDK_API int ZT_Certificate_encode( - const ZT_Certificate *cert, - void *encoded, - int *encodedSize); +ZT_SDK_API int ZT_Certificate_encode(const ZT_Certificate* cert, void* encoded, int* encodedSize); /** * Verify certificate signatures and internal structure. @@ -2993,9 +2877,7 @@ ZT_SDK_API int ZT_Certificate_encode( * @param clock Clock to check timestamp or -1 to skip this check * @return Certificate error or ZT_CERTIFICATE_ERROR_NONE if no errors found. */ -ZT_SDK_API enum ZT_CertificateError ZT_Certificate_verify( - const ZT_Certificate *cert, - int64_t clock); +ZT_SDK_API enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate* cert, int64_t clock); /** * Deep clone a certificate, returning one allocated C-side. @@ -3007,14 +2889,14 @@ ZT_SDK_API enum ZT_CertificateError ZT_Certificate_verify( * @param cert Certificate to deep clone * @return New certificate with copies of all objects */ -ZT_SDK_API const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert); +ZT_SDK_API const ZT_Certificate* ZT_Certificate_clone(const ZT_Certificate* cert); /** * Free a certificate created with ZT_Certificate_decode() or ZT_Certificate_clone() * * @param cert Certificate to free */ -ZT_SDK_API void ZT_Certificate_delete(const ZT_Certificate *cert); +ZT_SDK_API void ZT_Certificate_delete(const ZT_Certificate* cert); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -3026,7 +2908,7 @@ ZT_SDK_API void ZT_Certificate_delete(const ZT_Certificate *cert); * @param capacity Capacity, must be at least 128 bytes * @return Pointer to 'buf' now filled with a string */ -ZT_SDK_API char *ZT_Fingerprint_toString(const ZT_Fingerprint *fp, char *buf, int capacity); +ZT_SDK_API char* ZT_Fingerprint_toString(const ZT_Fingerprint* fp, char* buf, int capacity); /** * Decode a fingerprint from a string @@ -3035,7 +2917,7 @@ ZT_SDK_API char *ZT_Fingerprint_toString(const ZT_Fingerprint *fp, char *buf, in * @param s String representation of fingerprint * @return Non-zero on success */ -ZT_SDK_API int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s); +ZT_SDK_API int ZT_Fingerprint_fromString(ZT_Fingerprint* fp, const char* s); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -3045,30 +2927,30 @@ ZT_SDK_API int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s); * included. */ -#define ZT_InetAddress_ptr_cast_sockaddr_ptr(a) ((struct sockaddr *)(a)) -#define ZT_InetAddress_ptr_cast_sockaddr_in_ptr(a) ((struct sockaddr_in *)(a)) -#define ZT_InetAddress_ptr_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6 *)(a)) -#define ZT_InetAddress_ptr_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage *)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_ptr(a) ((struct sockaddr*)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_in_ptr(a) ((struct sockaddr_in*)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6*)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage*)(a)) -#define ZT_InetAddress_ptr_cast_const_sockaddr_ptr(a) ((const struct sockaddr *)(a)) -#define ZT_InetAddress_ptr_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in *)(a)) -#define ZT_InetAddress_ptr_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6 *)(a)) -#define ZT_InetAddress_ptr_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage *)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_ptr(a) ((const struct sockaddr*)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in*)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6*)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage*)(a)) -#define ZT_InetAddress_cast_sockaddr_ptr(a) ((struct sockaddr *)(&(a))) -#define ZT_InetAddress_cast_sockaddr_in_ptr(a) ((struct sockaddr_in *)(&(a))) -#define ZT_InetAddress_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6 *)(&(a))) -#define ZT_InetAddress_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage *)(&(a))) +#define ZT_InetAddress_cast_sockaddr_ptr(a) ((struct sockaddr*)(&(a))) +#define ZT_InetAddress_cast_sockaddr_in_ptr(a) ((struct sockaddr_in*)(&(a))) +#define ZT_InetAddress_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6*)(&(a))) +#define ZT_InetAddress_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage*)(&(a))) -#define ZT_InetAddress_cast_const_sockaddr_ptr(a) ((const struct sockaddr *)(&(a))) -#define ZT_InetAddress_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in *)(&(a))) -#define ZT_InetAddress_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6 *)(&(a))) -#define ZT_InetAddress_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage *)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_ptr(a) ((const struct sockaddr*)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in*)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6*)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage*)(&(a))) /** * Zero the contents of an InetAddress */ -ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress *ia); +ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress* ia); /** * Convert an IP/port pair to a string @@ -3078,7 +2960,7 @@ ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress *ia); * @param cap Size of buffer, must be at least 64 bytes * @return 'buf' is returned */ -ZT_SDK_API char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, unsigned int cap); +ZT_SDK_API char* ZT_InetAddress_toString(const ZT_InetAddress* ia, char* buf, unsigned int cap); /** * Parse an InetAddress in IP/port format @@ -3087,7 +2969,7 @@ ZT_SDK_API char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, un * @param str String to parse * @return Non-zero on success, zero if IP/port is invalid */ -ZT_SDK_API int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str); +ZT_SDK_API int ZT_InetAddress_fromString(ZT_InetAddress* ia, const char* str); /** * Set to the value of a sockaddr such as sockaddr_in or sockaddr_in6. @@ -3099,7 +2981,7 @@ ZT_SDK_API int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str); * @param ia InetAddress to fill * @param saddr A pointer to a sockaddr */ -ZT_SDK_API void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr); +ZT_SDK_API void ZT_InetAddress_set(ZT_InetAddress* ia, const void* saddr); /** * Set raw IP bytes @@ -3109,32 +2991,33 @@ ZT_SDK_API void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr); * @param ipLen Length of IP: 4 or 16 for IPv4 or IPv6 * @param port IP port */ -ZT_SDK_API void ZT_InetAddress_setIpBytes(ZT_InetAddress *ia, const void *ipBytes, unsigned int ipLen, unsigned int port); +ZT_SDK_API void +ZT_InetAddress_setIpBytes(ZT_InetAddress* ia, const void* ipBytes, unsigned int ipLen, unsigned int port); /** * Set IP port */ -ZT_SDK_API void ZT_InetAddress_setPort(ZT_InetAddress *ia, unsigned int port); +ZT_SDK_API void ZT_InetAddress_setPort(ZT_InetAddress* ia, unsigned int port); /** * Get IP port, which can also be used as a CIDR in some use cases. */ -ZT_SDK_API unsigned int ZT_InetAddress_port(const ZT_InetAddress *ia); +ZT_SDK_API unsigned int ZT_InetAddress_port(const ZT_InetAddress* ia); /** * Returns non-zero if this InetAddress is nil/zero. */ -ZT_SDK_API int ZT_InetAddress_isNil(const ZT_InetAddress *ia); +ZT_SDK_API int ZT_InetAddress_isNil(const ZT_InetAddress* ia); /** * Returns non-zero if this is an IPv4 address. */ -ZT_SDK_API int ZT_InetAddress_isV4(const ZT_InetAddress *ia); +ZT_SDK_API int ZT_InetAddress_isV4(const ZT_InetAddress* ia); /** * Returns non-zero if this is an IPv6 address. */ -ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia); +ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress* ia); /** * Fill buffer with IP address bytes, return length in bytes @@ -3143,12 +3026,12 @@ ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia); * @param buf Buffer with at least 16 bytes of space (to hold IPv6) * @return 0 on failure or nil, 4 if buf contains IPv4 IP, 16 if buf contains IPv6 IP */ -ZT_SDK_API unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress *ia, void *buf); +ZT_SDK_API unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress* ia, void* buf); /** * Classify the network scope of this IP address (local net, global, etc.) */ -ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia); +ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress* ia); /** * Compare a and b @@ -3157,10 +3040,10 @@ ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddre * @param b Second InetAddress * @return -1, 0, or 1 if a is less than, equal to, or greater than b */ -ZT_SDK_API int ZT_InetAddress_compare(const ZT_InetAddress *a, const ZT_InetAddress *b); +ZT_SDK_API int ZT_InetAddress_compare(const ZT_InetAddress* a, const ZT_InetAddress* b); /* These mirror the values of AF_INET and AF_INET6 for use by Rust and other things that need it. */ -ZT_SDK_API const int ZT_AF_INET,ZT_AF_INET6; +ZT_SDK_API const int ZT_AF_INET, ZT_AF_INET6; /* ---------------------------------------------------------------------------------------------------------------- */ @@ -3178,7 +3061,11 @@ ZT_SDK_API const int ZT_AF_INET,ZT_AF_INET6; * @param f Function to invoke with each key and (binary) value * @return Non-zero if dictionary was valid */ -ZT_SDK_API int ZT_Dictionary_parse(const void *dict, unsigned int len, void *arg, void (*f)(void *, const char *, unsigned int, const void *, unsigned int)); +ZT_SDK_API int ZT_Dictionary_parse( + const void* dict, + unsigned int len, + void* arg, + void (*f)(void*, const char*, unsigned int, const void*, unsigned int)); /* ---------------------------------------------------------------------------------------------------------------- */ diff --git a/osdep/CMakeLists.txt b/osdep/CMakeLists.txt index 39f47e094..a33775214 100644 --- a/osdep/CMakeLists.txt +++ b/osdep/CMakeLists.txt @@ -2,17 +2,17 @@ cmake_minimum_required(VERSION 3.0) project(zt_osdep) set(src -# ManagedRoute.cpp + # ManagedRoute.cpp OSUtils.cpp rust-osdep.cpp -) + ) set(headers -# ManagedRoute.hpp + # ManagedRoute.hpp OSUtils.hpp Thread.hpp rust-osdep.h -) + ) #if(WIN32) # set(src ${src} WindowsEthernetTap.cpp) diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 77157eae6..1b3bbb287 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -19,20 +19,20 @@ #include #ifdef __WINDOWS__ +#include #include #include #include -#include #endif #ifdef __UNIX_LIKE__ -#include +#include +#include #include #include #include #include -#include -#include +#include #ifndef ZT_SDK #include #endif @@ -44,11 +44,11 @@ #include #endif -#include +#include "ManagedRoute.hpp" + #include #include - -#include "ManagedRoute.hpp" +#include #ifdef __LINUX__ #include "LinuxNetLink.hpp" #endif @@ -61,340 +61,437 @@ namespace { // Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1 // If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't' -static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right) +static void _forkTarget(const InetAddress& t, InetAddress& left, InetAddress& right) { - const unsigned int bits = t.netmaskBits() + 1; - left = t; - if (t.ss_family == AF_INET) { - if (bits <= 32) { - left.setPort(bits); - right = t; - reinterpret_cast(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); - right.setPort(bits); - } else { - right.zero(); - } - } else if (t.ss_family == AF_INET6) { - if (bits <= 128) { - left.setPort(bits); - right = t; - uint8_t *b = reinterpret_cast(reinterpret_cast(&right)->sin6_addr.s6_addr); - b[bits / 8] ^= 1 << (8 - (bits % 8)); - right.setPort(bits); - } else { - right.zero(); - } - } + const unsigned int bits = t.netmaskBits() + 1; + left = t; + if (t.ss_family == AF_INET) { + if (bits <= 32) { + left.setPort(bits); + right = t; + reinterpret_cast(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); + right.setPort(bits); + } + else { + right.zero(); + } + } + else if (t.ss_family == AF_INET6) { + if (bits <= 128) { + left.setPort(bits); + right = t; + uint8_t* b = reinterpret_cast(reinterpret_cast(&right)->sin6_addr.s6_addr); + b[bits / 8] ^= 1 << (8 - (bits % 8)); + right.setPort(bits); + } + else { + right.zero(); + } + } } -struct _RTE -{ - InetAddress target; - InetAddress via; - char device[128]; - int metric; - bool ifscope; +struct _RTE { + InetAddress target; + InetAddress via; + char device[128]; + int metric; + bool ifscope; }; -#ifdef __BSD__ // ------------------------------------------------------------ +#ifdef __BSD__ // ------------------------------------------------------------ #define ZT_ROUTING_SUPPORT_FOUND 1 #ifndef ZT_SDK -static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains) +static std::vector<_RTE> _getRTEs(const InetAddress& target, bool contains) { - std::vector<_RTE> rtes; - int mib[6]; - size_t needed; + std::vector<_RTE> rtes; + int mib[6]; + size_t needed; - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (!sysctl(mib,6,NULL,&needed,NULL,0)) { - if (needed <= 0) - return rtes; + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (! sysctl(mib, 6, NULL, &needed, NULL, 0)) { + if (needed <= 0) + return rtes; - char *buf = (char *)::malloc(needed); - if (buf) { - if (!sysctl(mib,6,buf,&needed,NULL,0)) { - struct rt_msghdr *rtm; - for(char *next=buf,*end=buf+needed;nextrtm_msglen; + char* buf = (char*)::malloc(needed); + if (buf) { + if (! sysctl(mib, 6, buf, &needed, NULL, 0)) { + struct rt_msghdr* rtm; + for (char *next = buf, *end = buf + needed; next < end;) { + rtm = (struct rt_msghdr*)next; + char* saptr = (char*)(rtm + 1); + char* saend = next + rtm->rtm_msglen; - InetAddress sa_t,sa_v; - int deviceIndex = -9999; + InetAddress sa_t, sa_v; + int deviceIndex = -9999; - if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { - int which = 0; - while (saptr < saend) { - struct sockaddr *sa = (struct sockaddr *)saptr; - unsigned int salen = sa->sa_len; - if (!salen) - break; + if (((rtm->rtm_flags & RTF_LLINFO) == 0) && ((rtm->rtm_flags & RTF_HOST) == 0) + && ((rtm->rtm_flags & RTF_UP) != 0) && ((rtm->rtm_flags & RTF_MULTICAST) == 0)) { + int which = 0; + while (saptr < saend) { + struct sockaddr* sa = (struct sockaddr*)saptr; + unsigned int salen = sa->sa_len; + if (! salen) + break; - // Skip missing fields in rtm_addrs bit field - while ((rtm->rtm_addrs & 1) == 0) { - rtm->rtm_addrs >>= 1; - ++which; - if (which > 6) - break; - } - if (which > 6) - break; + // Skip missing fields in rtm_addrs bit field + while ((rtm->rtm_addrs & 1) == 0) { + rtm->rtm_addrs >>= 1; + ++which; + if (which > 6) + break; + } + if (which > 6) + break; - rtm->rtm_addrs >>= 1; - switch(which++) { - case 0: - //printf("RTA_DST\n"); - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { - // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec. - unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - if (!sin6->sin6_scope_id) - sin6->sin6_scope_id = interfaceIndex; - } - } - sa_t = *sa; - break; - case 1: - //printf("RTA_GATEWAY\n"); - switch(sa->sa_family) { - case AF_LINK: - deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; - break; - case AF_INET: - case AF_INET6: - sa_v = *sa; - break; - } - break; - case 2: { - //printf("RTA_NETMASK\n"); - if (sa_t.ss_family == AF_INET6) { - salen = sizeof(struct sockaddr_in6); - unsigned int bits = 0; - for(int i=0;i<16;++i) { - unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; - if (c == 0xff) - bits += 8; - else break; - } - sa_t.setPort(bits); - } else if (sa_t.ss_family == AF_INET) { - salen = sizeof(struct sockaddr_in); - sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); - } - } break; - /* - case 3: - //printf("RTA_GENMASK\n"); - break; - case 4: - //printf("RTA_IFP\n"); - break; - case 5: - //printf("RTA_IFA\n"); - break; - case 6: - //printf("RTA_AUTHOR\n"); - break; - */ - } + rtm->rtm_addrs >>= 1; + switch (which++) { + case 0: + // printf("RTA_DST\n"); + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; + if ((sin6->sin6_addr.s6_addr[0] == 0xfe) + && ((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { + // BSD uses this fucking strange in-band signaling method to encode device + // scope IDs for IPv6 addresses... probably a holdover from very early + // versions of the spec. + unsigned int interfaceIndex = + ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) + | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + if (! sin6->sin6_scope_id) + sin6->sin6_scope_id = interfaceIndex; + } + } + sa_t = *sa; + break; + case 1: + // printf("RTA_GATEWAY\n"); + switch (sa->sa_family) { + case AF_LINK: + deviceIndex = (int)((const struct sockaddr_dl*)sa)->sdl_index; + break; + case AF_INET: + case AF_INET6: + sa_v = *sa; + break; + } + break; + case 2: { + // printf("RTA_NETMASK\n"); + if (sa_t.ss_family == AF_INET6) { + salen = sizeof(struct sockaddr_in6); + unsigned int bits = 0; + for (int i = 0; i < 16; ++i) { + unsigned char c = + (unsigned char)((const struct sockaddr_in6*)sa)->sin6_addr.s6_addr[i]; + if (c == 0xff) + bits += 8; + else + break; + } + sa_t.setPort(bits); + } + else if (sa_t.ss_family == AF_INET) { + salen = sizeof(struct sockaddr_in); + sa_t.setPort((unsigned int)Utils::countBits( + (uint32_t)((const struct sockaddr_in*)sa)->sin_addr.s_addr)); + } + } break; + /* + case 3: + //printf("RTA_GENMASK\n"); + break; + case 4: + //printf("RTA_IFP\n"); + break; + case 5: + //printf("RTA_IFA\n"); + break; + case 6: + //printf("RTA_AUTHOR\n"); + break; + */ + } - saptr += salen; - } + saptr += salen; + } - if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) { - rtes.push_back(_RTE()); - rtes.back().target = sa_t; - rtes.back().via = sa_v; - if (deviceIndex >= 0) { - if_indextoname(deviceIndex,rtes.back().device); - } else { - rtes.back().device[0] = (char)0; - } - rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; - } - } + if (((contains) && (sa_t.containsAddress(target))) || (sa_t == target)) { + rtes.push_back(_RTE()); + rtes.back().target = sa_t; + rtes.back().via = sa_v; + if (deviceIndex >= 0) { + if_indextoname(deviceIndex, rtes.back().device); + } + else { + rtes.back().device[0] = (char)0; + } + rtes.back().metric = + ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; + } + } - next = saend; - } - } + next = saend; + } + } - ::free(buf); - } - } + ::free(buf); + } + } - return rtes; + return rtes; } #endif -static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface) +static void _routeCmd( + const char* op, + const InetAddress& target, + const InetAddress& via, + const char* ifscope, + const char* localInterface) { - //char f1[1024],f2[1024]; printf("%s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface); - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - char ttmp[64]; - char iptmp[64]; - if (via) { - if ((ifscope)&&(ifscope[0])) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0); - } else { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0); - } - } else if ((localInterface)&&(localInterface[0])) { - if ((ifscope)&&(ifscope[0])) { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); - } else { - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); - } - } - ::_exit(-1); - } + // char f1[1024],f2[1024]; printf("%s %s %s %s + // %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface); + long p = (long)fork(); + if (p > 0) { + int exitcode = -1; + ::waitpid(p, &exitcode, 0); + } + else if (p == 0) { + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + char ttmp[64]; + char iptmp[64]; + if (via) { + if ((ifscope) && (ifscope[0])) { + ::execl( + ZT_BSD_ROUTE_CMD, + ZT_BSD_ROUTE_CMD, + op, + "-ifscope", + ifscope, + ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), + target.toString(ttmp), + via.toIpString(iptmp), + (const char*)0); + } + else { + ::execl( + ZT_BSD_ROUTE_CMD, + ZT_BSD_ROUTE_CMD, + op, + ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), + target.toString(ttmp), + via.toIpString(iptmp), + (const char*)0); + } + } + else if ((localInterface) && (localInterface[0])) { + if ((ifscope) && (ifscope[0])) { + ::execl( + ZT_BSD_ROUTE_CMD, + ZT_BSD_ROUTE_CMD, + op, + "-ifscope", + ifscope, + ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), + target.toString(ttmp), + "-interface", + localInterface, + (const char*)0); + } + else { + ::execl( + ZT_BSD_ROUTE_CMD, + ZT_BSD_ROUTE_CMD, + op, + ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), + target.toString(ttmp), + "-interface", + localInterface, + (const char*)0); + } + } + ::_exit(-1); + } } -#endif // __BSD__ ------------------------------------------------------------ +#endif // __BSD__ ------------------------------------------------------------ -#ifdef __LINUX__ // ---------------------------------------------------------- +#ifdef __LINUX__ // ---------------------------------------------------------- #define ZT_ROUTING_SUPPORT_FOUND 1 // This has been replaced by LinuxNetLink -#endif // __LINUX__ ---------------------------------------------------------- +#endif // __LINUX__ ---------------------------------------------------------- -#ifdef __WINDOWS__ // -------------------------------------------------------- +#ifdef __WINDOWS__ // -------------------------------------------------------- #define ZT_ROUTING_SUPPORT_FOUND 1 -static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via) +static bool _winRoute( + bool del, + const NET_LUID& interfaceLuid, + const NET_IFINDEX& interfaceIndex, + const InetAddress& target, + const InetAddress& via) { - MIB_IPFORWARD_ROW2 rtrow; - InitializeIpForwardEntry(&rtrow); - rtrow.InterfaceLuid.Value = interfaceLuid.Value; - rtrow.InterfaceIndex = interfaceIndex; - if (target.ss_family == AF_INET) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; - if (via.ss_family == AF_INET) { - rtrow.NextHop.si_family = AF_INET; - rtrow.NextHop.Ipv4.sin_family = AF_INET; - rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; - } - } else if (target.ss_family == AF_INET6) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; - rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&target)->sin6_addr.u.Byte,16); - if (via.ss_family == AF_INET6) { - rtrow.NextHop.si_family = AF_INET6; - rtrow.NextHop.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&via)->sin6_addr.u.Byte,16); - } - } else { - return false; - } - rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); - rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; - rtrow.ValidLifetime = 0xffffffff; - rtrow.PreferredLifetime = 0xffffffff; - rtrow.Metric = -1; - rtrow.Protocol = MIB_IPPROTO_NETMGMT; - rtrow.Loopback = FALSE; - rtrow.AutoconfigureAddress = FALSE; - rtrow.Publish = FALSE; - rtrow.Immortal = FALSE; - rtrow.Age = 0; - rtrow.Origin = NlroManual; - if (del) { - return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - NTSTATUS r = CreateIpForwardEntry2(&rtrow); - if (r == NO_ERROR) { - return true; - } else if (r == ERROR_OBJECT_ALREADY_EXISTS) { - return (SetIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - return false; - } - } + MIB_IPFORWARD_ROW2 rtrow; + InitializeIpForwardEntry(&rtrow); + rtrow.InterfaceLuid.Value = interfaceLuid.Value; + rtrow.InterfaceIndex = interfaceIndex; + if (target.ss_family == AF_INET) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = + reinterpret_cast(&target)->sin_addr.S_un.S_addr; + if (via.ss_family == AF_INET) { + rtrow.NextHop.si_family = AF_INET; + rtrow.NextHop.Ipv4.sin_family = AF_INET; + rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = + reinterpret_cast(&via)->sin_addr.S_un.S_addr; + } + } + else if (target.ss_family == AF_INET6) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; + memcpy( + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, + reinterpret_cast(&target)->sin6_addr.u.Byte, + 16); + if (via.ss_family == AF_INET6) { + rtrow.NextHop.si_family = AF_INET6; + rtrow.NextHop.Ipv6.sin6_family = AF_INET6; + memcpy( + rtrow.NextHop.Ipv6.sin6_addr.u.Byte, + reinterpret_cast(&via)->sin6_addr.u.Byte, + 16); + } + } + else { + return false; + } + rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); + rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; + rtrow.ValidLifetime = 0xffffffff; + rtrow.PreferredLifetime = 0xffffffff; + rtrow.Metric = -1; + rtrow.Protocol = MIB_IPPROTO_NETMGMT; + rtrow.Loopback = FALSE; + rtrow.AutoconfigureAddress = FALSE; + rtrow.Publish = FALSE; + rtrow.Immortal = FALSE; + rtrow.Age = 0; + rtrow.Origin = NlroManual; + if (del) { + return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); + } + else { + NTSTATUS r = CreateIpForwardEntry2(&rtrow); + if (r == NO_ERROR) { + return true; + } + else if (r == ERROR_OBJECT_ALREADY_EXISTS) { + return (SetIpForwardEntry2(&rtrow) == NO_ERROR); + } + else { + return false; + } + } } -static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via) +static bool _winHasRoute( + const NET_LUID& interfaceLuid, + const NET_IFINDEX& interfaceIndex, + const InetAddress& target, + const InetAddress& via) { - MIB_IPFORWARD_ROW2 rtrow; - InitializeIpForwardEntry(&rtrow); - rtrow.InterfaceLuid.Value = interfaceLuid.Value; - rtrow.InterfaceIndex = interfaceIndex; - if (target.ss_family == AF_INET) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; - if (via.ss_family == AF_INET) { - rtrow.NextHop.si_family = AF_INET; - rtrow.NextHop.Ipv4.sin_family = AF_INET; - rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; - } - } else if (target.ss_family == AF_INET6) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; - rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&target)->sin6_addr.u.Byte, 16); - if (via.ss_family == AF_INET6) { - rtrow.NextHop.si_family = AF_INET6; - rtrow.NextHop.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&via)->sin6_addr.u.Byte, 16); - } - } else { - return false; - } - rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); - rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; - return (GetIpForwardEntry2(&rtrow) == NO_ERROR); + MIB_IPFORWARD_ROW2 rtrow; + InitializeIpForwardEntry(&rtrow); + rtrow.InterfaceLuid.Value = interfaceLuid.Value; + rtrow.InterfaceIndex = interfaceIndex; + if (target.ss_family == AF_INET) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = + reinterpret_cast(&target)->sin_addr.S_un.S_addr; + if (via.ss_family == AF_INET) { + rtrow.NextHop.si_family = AF_INET; + rtrow.NextHop.Ipv4.sin_family = AF_INET; + rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = + reinterpret_cast(&via)->sin_addr.S_un.S_addr; + } + } + else if (target.ss_family == AF_INET6) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; + memcpy( + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, + reinterpret_cast(&target)->sin6_addr.u.Byte, + 16); + if (via.ss_family == AF_INET6) { + rtrow.NextHop.si_family = AF_INET6; + rtrow.NextHop.Ipv6.sin6_family = AF_INET6; + memcpy( + rtrow.NextHop.Ipv6.sin6_addr.u.Byte, + reinterpret_cast(&via)->sin6_addr.u.Byte, + 16); + } + } + else { + return false; + } + rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); + rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; + return (GetIpForwardEntry2(&rtrow) == NO_ERROR); } -#endif // __WINDOWS__ -------------------------------------------------------- +#endif // __WINDOWS__ -------------------------------------------------------- #ifndef ZT_ROUTING_SUPPORT_FOUND -#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS." +#error \ + "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS." #endif -} // anonymous namespace +} // anonymous namespace -ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device) +ManagedRoute::ManagedRoute( + const InetAddress& target, + const InetAddress& via, + const InetAddress& src, + const char* device) { - _target = target; - _via = via; - _src = src; + _target = target; + _via = via; + _src = src; - if (_via.ss_family == AF_INET) { - _via.setPort(32); - } else if (_via.ss_family == AF_INET6) { - _via.setPort(128); - } + if (_via.ss_family == AF_INET) { + _via.setPort(32); + } + else if (_via.ss_family == AF_INET6) { + _via.setPort(128); + } - if (_src.ss_family == AF_INET) { - _src.setPort(32); - } else if (_src.ss_family == AF_INET6) { - _src.setPort(128); - } + if (_src.ss_family == AF_INET) { + _src.setPort(32); + } + else if (_src.ss_family == AF_INET6) { + _src.setPort(128); + } - Utils::scopy(_device,sizeof(_device),device); - _systemDevice[0] = (char)0; + Utils::scopy(_device, sizeof(_device), device); + _systemDevice[0] = (char)0; } ManagedRoute::~ManagedRoute() { - this->remove(); + this->remove(); } /* Linux NOTE: for default route override, some Linux distributions will @@ -413,157 +510,160 @@ ManagedRoute::~ManagedRoute() bool ManagedRoute::sync() { #ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return false; + NET_LUID interfaceLuid; + interfaceLuid.Value = (ULONG64)Utils::hexStrToU64( + _device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute + NET_IFINDEX interfaceIndex = -1; + if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR) + return false; #endif - InetAddress leftt,rightt; - if (_target.netmaskBits() == 0) // bifurcate only the default route - _forkTarget(_target,leftt,rightt); - else leftt = _target; + InetAddress leftt, rightt; + if (_target.netmaskBits() == 0) // bifurcate only the default route + _forkTarget(_target, leftt, rightt); + else + leftt = _target; -#ifdef __BSD__ // ------------------------------------------------------------ +#ifdef __BSD__ // ------------------------------------------------------------ - // Find lowest metric system route that this route should override (if any) - InetAddress newSystemVia; - char newSystemDevice[128]; - newSystemDevice[0] = (char)0; - int systemMetric = 9999999; - std::vector<_RTE> rtes(_getRTEs(_target,false)); - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if (r->via) { - if ( ((!newSystemVia)||(r->metric < systemMetric)) && (strcmp(r->device,_device) != 0) ) { - newSystemVia = r->via; - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - systemMetric = r->metric; - } - } - } + // Find lowest metric system route that this route should override (if any) + InetAddress newSystemVia; + char newSystemDevice[128]; + newSystemDevice[0] = (char)0; + int systemMetric = 9999999; + std::vector<_RTE> rtes(_getRTEs(_target, false)); + for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) { + if (r->via) { + if (((! newSystemVia) || (r->metric < systemMetric)) && (strcmp(r->device, _device) != 0)) { + newSystemVia = r->via; + Utils::scopy(newSystemDevice, sizeof(newSystemDevice), r->device); + systemMetric = r->metric; + } + } + } - // Get device corresponding to route if we don't have that already - if ((newSystemVia)&&(!newSystemDevice[0])) { - rtes = _getRTEs(newSystemVia,true); - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if ( (r->device[0]) && (strcmp(r->device,_device) != 0) ) { - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - break; - } - } - } - if (!newSystemDevice[0]) - newSystemVia.zero(); + // Get device corresponding to route if we don't have that already + if ((newSystemVia) && (! newSystemDevice[0])) { + rtes = _getRTEs(newSystemVia, true); + for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) { + if ((r->device[0]) && (strcmp(r->device, _device) != 0)) { + Utils::scopy(newSystemDevice, sizeof(newSystemDevice), r->device); + break; + } + } + } + if (! newSystemDevice[0]) + newSystemVia.zero(); - // Shadow system route if it exists, also delete any obsolete shadows - // and replace them with the new state. sync() is called periodically to - // allow us to do that if underlying connectivity changes. - if ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice) != 0)) { - if (_systemVia) { - _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) - _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0); - } + // Shadow system route if it exists, also delete any obsolete shadows + // and replace them with the new state. sync() is called periodically to + // allow us to do that if underlying connectivity changes. + if ((_systemVia != newSystemVia) || (strcmp(_systemDevice, newSystemDevice) != 0)) { + if (_systemVia) { + _routeCmd("delete", leftt, _systemVia, _systemDevice, (const char*)0); + if (rightt) + _routeCmd("delete", rightt, _systemVia, _systemDevice, (const char*)0); + } - _systemVia = newSystemVia; - Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); + _systemVia = newSystemVia; + Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice); - if (_systemVia) { - _routeCmd("add",leftt,_systemVia,_systemDevice,(const char *)0); - _routeCmd("change",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) { - _routeCmd("add",rightt,_systemVia,_systemDevice,(const char *)0); - _routeCmd("change",rightt,_systemVia,_systemDevice,(const char *)0); - } - } - } + if (_systemVia) { + _routeCmd("add", leftt, _systemVia, _systemDevice, (const char*)0); + _routeCmd("change", leftt, _systemVia, _systemDevice, (const char*)0); + if (rightt) { + _routeCmd("add", rightt, _systemVia, _systemDevice, (const char*)0); + _routeCmd("change", rightt, _systemVia, _systemDevice, (const char*)0); + } + } + } - if (!_applied.count(leftt)) { - _applied[leftt] = false; // not ifscoped - _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - _routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied[rightt] = false; // not ifscoped - _routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - _routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - } + if (! _applied.count(leftt)) { + _applied[leftt] = false; // not ifscoped + _routeCmd("add", leftt, _via, (const char*)0, (_via) ? (const char*)0 : _device); + _routeCmd("change", leftt, _via, (const char*)0, (_via) ? (const char*)0 : _device); + } + if ((rightt) && (! _applied.count(rightt))) { + _applied[rightt] = false; // not ifscoped + _routeCmd("add", rightt, _via, (const char*)0, (_via) ? (const char*)0 : _device); + _routeCmd("change", rightt, _via, (const char*)0, (_via) ? (const char*)0 : _device); + } -#endif // __BSD__ ------------------------------------------------------------ +#endif // __BSD__ ------------------------------------------------------------ -#ifdef __LINUX__ // ---------------------------------------------------------- +#ifdef __LINUX__ // ---------------------------------------------------------- - const char *const devptr = (_via) ? (const char *)0 : _device; - if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,devptr))) { - _applied[leftt] = false; // boolean unused - LinuxNetLink::getInstance().addRoute(leftt, _via, _src, devptr); - } - if ((rightt)&&(!LinuxNetLink::getInstance().routeIsSet(rightt,_via,_src,devptr))) { - _applied[rightt] = false; // boolean unused - LinuxNetLink::getInstance().addRoute(rightt, _via, _src, devptr); - } + const char* const devptr = (_via) ? (const char*)0 : _device; + if ((leftt) && (! LinuxNetLink::getInstance().routeIsSet(leftt, _via, _src, devptr))) { + _applied[leftt] = false; // boolean unused + LinuxNetLink::getInstance().addRoute(leftt, _via, _src, devptr); + } + if ((rightt) && (! LinuxNetLink::getInstance().routeIsSet(rightt, _via, _src, devptr))) { + _applied[rightt] = false; // boolean unused + LinuxNetLink::getInstance().addRoute(rightt, _via, _src, devptr); + } -#endif // __LINUX__ ---------------------------------------------------------- +#endif // __LINUX__ ---------------------------------------------------------- -#ifdef __WINDOWS__ // -------------------------------------------------------- +#ifdef __WINDOWS__ // -------------------------------------------------------- - if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) { - _applied[leftt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); - } - if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) { - _applied[rightt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); - } + if ((! _applied.count(leftt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, leftt, _via))) { + _applied[leftt] = false; // boolean unused + _winRoute(false, interfaceLuid, interfaceIndex, leftt, _via); + } + if ((rightt) && ((! _applied.count(rightt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, rightt, _via)))) { + _applied[rightt] = false; // boolean unused + _winRoute(false, interfaceLuid, interfaceIndex, rightt, _via); + } -#endif // __WINDOWS__ -------------------------------------------------------- +#endif // __WINDOWS__ -------------------------------------------------------- - return true; + return true; } #endif void ManagedRoute::remove() { #ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return; + NET_LUID interfaceLuid; + interfaceLuid.Value = (ULONG64)Utils::hexStrToU64( + _device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute + NET_IFINDEX interfaceIndex = -1; + if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR) + return; #endif #ifdef __BSD__ - if (_systemVia) { - InetAddress leftt,rightt; - _forkTarget(_target,leftt,rightt); - _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0); - if (rightt) - _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0); - } -#endif // __BSD__ ------------------------------------------------------------ + if (_systemVia) { + InetAddress leftt, rightt; + _forkTarget(_target, leftt, rightt); + _routeCmd("delete", leftt, _systemVia, _systemDevice, (const char*)0); + if (rightt) + _routeCmd("delete", rightt, _systemVia, _systemDevice, (const char*)0); + } +#endif // __BSD__ ------------------------------------------------------------ - for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { -#ifdef __BSD__ // ------------------------------------------------------------ - _routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device); -#endif // __BSD__ ------------------------------------------------------------ + for (std::map::iterator r(_applied.begin()); r != _applied.end(); ++r) { +#ifdef __BSD__ // ------------------------------------------------------------ + _routeCmd("delete", r->first, _via, r->second ? _device : (const char*)0, (_via) ? (const char*)0 : _device); +#endif // __BSD__ ------------------------------------------------------------ -#ifdef __LINUX__ // ---------------------------------------------------------- - //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); - LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device); -#endif // __LINUX__ ---------------------------------------------------------- +#ifdef __LINUX__ // ---------------------------------------------------------- + //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); + LinuxNetLink::getInstance().delRoute(r->first, _via, _src, (_via) ? (const char*)0 : _device); +#endif // __LINUX__ ---------------------------------------------------------- -#ifdef __WINDOWS__ // -------------------------------------------------------- - _winRoute(true,interfaceLuid,interfaceIndex,r->first,_via); -#endif // __WINDOWS__ -------------------------------------------------------- - } +#ifdef __WINDOWS__ // -------------------------------------------------------- + _winRoute(true, interfaceLuid, interfaceIndex, r->first, _via); +#endif // __WINDOWS__ -------------------------------------------------------- + } - _target.zero(); - _via.zero(); - _systemVia.zero(); - _device[0] = (char)0; - _systemDevice[0] = (char)0; - _applied.clear(); + _target.zero(); + _via.zero(); + _systemVia.zero(); + _device[0] = (char)0; + _systemDevice[0] = (char)0; + _applied.clear(); } -} // namespace ZeroTier \ No newline at end of file +} // namespace ZeroTier \ No newline at end of file diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 4cadedaa7..11fda77fc 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -14,70 +14,85 @@ #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP +#include "../node/AtomicCounter.hpp" +#include "../node/InetAddress.hpp" +#include "../node/SharedPtr.hpp" +#include "../node/Utils.hpp" + +#include +#include #include #include - -#include "../node/InetAddress.hpp" -#include "../node/Utils.hpp" -#include "../node/SharedPtr.hpp" -#include "../node/AtomicCounter.hpp" - -#include #include -#include namespace ZeroTier { /** * A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate */ -class ManagedRoute -{ - friend class SharedPtr; +class ManagedRoute { + friend class SharedPtr; -public: - ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device); - ~ManagedRoute(); + public: + ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device); + ~ManagedRoute(); - /** - * Set or update currently set route - * - * This must be called periodically for routes that shadow others so that - * shadow routes can be updated. In some cases it has no effect - * - * @return True if route add/update was successful - */ - bool sync(); + /** + * Set or update currently set route + * + * This must be called periodically for routes that shadow others so that + * shadow routes can be updated. In some cases it has no effect + * + * @return True if route add/update was successful + */ + bool sync(); - /** - * Remove and clear this ManagedRoute - * - * This does nothing if this ManagedRoute is not set or has already been - * removed. If this is not explicitly called it is called automatically on - * destruct. - */ - void remove(); + /** + * Remove and clear this ManagedRoute + * + * This does nothing if this ManagedRoute is not set or has already been + * removed. If this is not explicitly called it is called automatically on + * destruct. + */ + void remove(); - inline const InetAddress &target() const { return _target; } - inline const InetAddress &via() const { return _via; } - inline const InetAddress &src() const { return _src; } - inline const char *device() const { return _device; } + inline const InetAddress& target() const + { + return _target; + } + inline const InetAddress& via() const + { + return _via; + } + inline const InetAddress& src() const + { + return _src; + } + inline const char* device() const + { + return _device; + } -private: - ManagedRoute(const ManagedRoute &) {} - inline ManagedRoute &operator=(const ManagedRoute &) { return *this; } + private: + ManagedRoute(const ManagedRoute&) + { + } + inline ManagedRoute& operator=(const ManagedRoute&) + { + return *this; + } - InetAddress _target; - InetAddress _via; - InetAddress _src; - InetAddress _systemVia; // for route overrides - std::map _applied; // routes currently applied - char _device[128]; - char _systemDevice[128]; // for route overrides + InetAddress _target; + InetAddress _via; + InetAddress _src; + InetAddress _systemVia; // for route overrides + std::map _applied; // routes currently applied + char _device[128]; + char _systemDevice[128]; // for route overrides - AtomicCounter __refCount; + AtomicCounter __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 127c92225..889d498f8 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -11,9 +11,10 @@ */ /****/ +#include "OSUtils.hpp" + #include "../core/Constants.hpp" #include "../core/Containers.hpp" -#include "OSUtils.hpp" #include @@ -37,16 +38,16 @@ namespace ZeroTier { static clock_serv_t _machGetRealtimeClock() noexcept { - clock_serv_t c; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &c); - return c; + clock_serv_t c; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &c); + return c; } static clock_serv_t _machGetMonotonicClock() noexcept { - clock_serv_t c; - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &c); - return c; + clock_serv_t c; + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &c); + return c; } clock_serv_t OSUtils::s_machRealtimeClock = _machGetRealtimeClock(); @@ -54,315 +55,352 @@ clock_serv_t OSUtils::s_machMonotonicClock = _machGetMonotonicClock(); #endif -unsigned int OSUtils::ztsnprintf(char *buf, unsigned int len, const char *fmt, ...) +unsigned int OSUtils::ztsnprintf(char* buf, unsigned int len, const char* fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - int n = (int)vsnprintf(buf, len, fmt, ap); - va_end(ap); + va_start(ap, fmt); + int n = (int)vsnprintf(buf, len, fmt, ap); + va_end(ap); - if ((n >= (int)len) || (n < 0)) { - if (len) - buf[len - 1] = (char)0; - throw std::length_error("buf[] overflow"); - } + if ((n >= (int)len) || (n < 0)) { + if (len) + buf[len - 1] = (char)0; + throw std::length_error("buf[] overflow"); + } - return (unsigned int)n; + return (unsigned int)n; } #ifdef __UNIX_LIKE__ -bool OSUtils::redirectUnixOutputs(const char *stdoutPath, const char *stderrPath) +bool OSUtils::redirectUnixOutputs(const char* stdoutPath, const char* stderrPath) { - int fdout = open(stdoutPath, O_WRONLY | O_CREAT, 0600); - if (fdout > 0) { - int fderr; - if (stderrPath) { - fderr = open(stderrPath, O_WRONLY | O_CREAT, 0600); - if (fderr <= 0) { - ::close(fdout); - return false; - } - } else fderr = fdout; - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - ::dup2(fdout, STDOUT_FILENO); - ::dup2(fderr, STDERR_FILENO); - return true; - } - return false; + int fdout = open(stdoutPath, O_WRONLY | O_CREAT, 0600); + if (fdout > 0) { + int fderr; + if (stderrPath) { + fderr = open(stderrPath, O_WRONLY | O_CREAT, 0600); + if (fderr <= 0) { + ::close(fdout); + return false; + } + } + else + fderr = fdout; + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + ::dup2(fdout, STDOUT_FILENO); + ::dup2(fderr, STDERR_FILENO); + return true; + } + return false; } -#endif // __UNIX_LIKE__ +#endif // __UNIX_LIKE__ -Vector< String > OSUtils::listDirectory(const char *path, bool includeDirectories) +Vector OSUtils::listDirectory(const char* path, bool includeDirectories) { - Vector< String > r; + Vector r; #ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((String(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ( (strcmp(ffd.cFileName,".")) && (strcmp(ffd.cFileName,"..")) && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)||(((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)&&(includeDirectories))) ) - r.push_back(String(ffd.cFileName)); - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } + HANDLE hFind; + WIN32_FIND_DATAA ffd; + if ((hFind = FindFirstFileA((String(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName, ".")) && (strcmp(ffd.cFileName, "..")) + && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + || (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && (includeDirectories)))) + r.push_back(String(ffd.cFileName)); + } while (FindNextFileA(hFind, &ffd)); + FindClose(hFind); + } #else - dirent de; - dirent *dptr; - DIR *d = opendir(path); - if (!d) - return r; - dptr = (struct dirent *)0; - for (;;) { - if (readdir_r(d, &de, &dptr)) - break; - if (dptr) { - if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) && ((dptr->d_type != DT_DIR) || (includeDirectories))) - r.push_back(String(dptr->d_name)); - } else break; - } - closedir(d); + dirent de; + dirent* dptr; + DIR* d = opendir(path); + if (! d) + return r; + dptr = (struct dirent*)0; + for (;;) { + if (readdir_r(d, &de, &dptr)) + break; + if (dptr) { + if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) + && ((dptr->d_type != DT_DIR) || (includeDirectories))) + r.push_back(String(dptr->d_name)); + } + else + break; + } + closedir(d); #endif - return r; + return r; } -bool OSUtils::rmDashRf(const char *path) +bool OSUtils::rmDashRf(const char* path) { #ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((String(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,".") != 0)&&(strcmp(ffd.cFileName,"..") != 0)) { - if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - if (DeleteFileA((String(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE) - return false; - } else { - if (!rmDashRf((String(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str())) - return false; - } - } - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } - return (RemoveDirectoryA(path) != FALSE); + HANDLE hFind; + WIN32_FIND_DATAA ffd; + if ((hFind = FindFirstFileA((String(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName, ".") != 0) && (strcmp(ffd.cFileName, "..") != 0)) { + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + if (DeleteFileA((String(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE) + return false; + } + else { + if (! rmDashRf((String(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str())) + return false; + } + } + } while (FindNextFileA(hFind, &ffd)); + FindClose(hFind); + } + return (RemoveDirectoryA(path) != FALSE); #else - dirent de; - dirent *dptr; - DIR *d = opendir(path); - if (!d) - return true; - dptr = (struct dirent *)0; - for (;;) { - if (readdir_r(d, &de, &dptr) != 0) - break; - if (!dptr) - break; - if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) && (strlen(dptr->d_name) > 0)) { - String p(path); - p.push_back(ZT_PATH_SEPARATOR); - p.append(dptr->d_name); - if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them - if (!rmDashRf(p.c_str())) - return false; - } - } - } - closedir(d); - return (rmdir(path) == 0); + dirent de; + dirent* dptr; + DIR* d = opendir(path); + if (! d) + return true; + dptr = (struct dirent*)0; + for (;;) { + if (readdir_r(d, &de, &dptr) != 0) + break; + if (! dptr) + break; + if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) && (strlen(dptr->d_name) > 0)) { + String p(path); + p.push_back(ZT_PATH_SEPARATOR); + p.append(dptr->d_name); + if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them + if (! rmDashRf(p.c_str())) + return false; + } + } + } + closedir(d); + return (rmdir(path) == 0); #endif } -void OSUtils::lockDownFile(const char *path, bool isDir) +void OSUtils::lockDownFile(const char* path, bool isDir) { #ifdef __UNIX_LIKE__ - chmod(path, isDir ? 0700 : 0600); + chmod(path, isDir ? 0700 : 0600); #else #ifdef __WINDOWS__ - { - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; + { + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(String("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + if (CreateProcessA( + NULL, + (LPSTR)(String("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(), + NULL, + NULL, + FALSE, + CREATE_NO_WINDOW, + NULL, + NULL, + &startupInfo, + &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(String("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - } + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + if (CreateProcessA( + NULL, + (LPSTR)(String("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(), + NULL, + NULL, + FALSE, + CREATE_NO_WINDOW, + NULL, + NULL, + &startupInfo, + &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + } #endif #endif } -bool OSUtils::fileExists(const char *path, bool followLinks) +bool OSUtils::fileExists(const char* path, bool followLinks) { - struct stat s; + struct stat s; #ifdef __UNIX_LIKE__ - if (!followLinks) - return (lstat(path, &s) == 0); + if (! followLinks) + return (lstat(path, &s) == 0); #endif - return (stat(path, &s) == 0); + return (stat(path, &s) == 0); } -bool OSUtils::readFile(const char *path, String &buf) +bool OSUtils::readFile(const char* path, String& buf) { - char tmp[16384]; - FILE *f = fopen(path, "rb"); - if (f) { - for (;;) { - long n = (long)fread(tmp, 1, sizeof(tmp), f); - if (n > 0) - buf.append(tmp, n); - else break; - } - fclose(f); - return true; - } - return false; + char tmp[16384]; + FILE* f = fopen(path, "rb"); + if (f) { + for (;;) { + long n = (long)fread(tmp, 1, sizeof(tmp), f); + if (n > 0) + buf.append(tmp, n); + else + break; + } + fclose(f); + return true; + } + return false; } -bool OSUtils::writeFile(const char *path, const void *buf, unsigned int len) +bool OSUtils::writeFile(const char* path, const void* buf, unsigned int len) { - FILE *f = fopen(path, "wb"); - if (f) { - if ((long)fwrite(buf, 1, len, f) != (long)len) { - fclose(f); - return false; - } else { - fclose(f); - return true; - } - } - return false; + FILE* f = fopen(path, "wb"); + if (f) { + if ((long)fwrite(buf, 1, len, f) != (long)len) { + fclose(f); + return false; + } + else { + fclose(f); + return true; + } + } + return false; } -Vector< String > OSUtils::split(const char *s, const char *const sep, const char *esc, const char *quot) +Vector OSUtils::split(const char* s, const char* const sep, const char* esc, const char* quot) { - Vector< String > fields; - String buf; + Vector fields; + String buf; - if (!esc) - esc = ""; - if (!quot) - quot = ""; + if (! esc) + esc = ""; + if (! quot) + quot = ""; - bool escapeState = false; - char quoteState = 0; - while (*s) { - if (escapeState) { - escapeState = false; - buf.push_back(*s); - } else if (quoteState) { - if (*s == quoteState) { - quoteState = 0; - fields.push_back(buf); - buf.clear(); - } else buf.push_back(*s); - } else { - const char *quotTmp; - if (strchr(esc, *s)) - escapeState = true; - else if ((buf.size() <= 0) && ((quotTmp = strchr(quot, *s)))) - quoteState = *quotTmp; - else if (strchr(sep, *s)) { - if (buf.size() > 0) { - fields.push_back(buf); - buf.clear(); - } // else skip runs of separators - } else buf.push_back(*s); - } - ++s; - } + bool escapeState = false; + char quoteState = 0; + while (*s) { + if (escapeState) { + escapeState = false; + buf.push_back(*s); + } + else if (quoteState) { + if (*s == quoteState) { + quoteState = 0; + fields.push_back(buf); + buf.clear(); + } + else + buf.push_back(*s); + } + else { + const char* quotTmp; + if (strchr(esc, *s)) + escapeState = true; + else if ((buf.size() <= 0) && ((quotTmp = strchr(quot, *s)))) + quoteState = *quotTmp; + else if (strchr(sep, *s)) { + if (buf.size() > 0) { + fields.push_back(buf); + buf.clear(); + } // else skip runs of separators + } + else + buf.push_back(*s); + } + ++s; + } - if (buf.size()) - fields.push_back(buf); + if (buf.size()) + fields.push_back(buf); - return fields; + return fields; } ZeroTier::String OSUtils::platformDefaultHomePath() { #ifdef __QNAP__ - char *cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; - char buf[128]; - FILE *fp; - if ((fp = popen(cmd, "r")) == NULL) { - printf("Error opening pipe!\n"); - return NULL; - } - while (fgets(buf, 128, fp) != NULL) { } - if(pclose(fp)) { - printf("Command not found or exited with error status\n"); - return NULL; - } - String homeDir = String(buf); - homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end()); - return homeDir; + char* cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; + char buf[128]; + FILE* fp; + if ((fp = popen(cmd, "r")) == NULL) { + printf("Error opening pipe!\n"); + return NULL; + } + while (fgets(buf, 128, fp) != NULL) {} + if (pclose(fp)) { + printf("Command not found or exited with error status\n"); + return NULL; + } + String homeDir = String(buf); + homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end()); + return homeDir; #endif - // Check for user-defined environment variable before using defaults + // Check for user-defined environment variable before using defaults #ifdef __WINDOWS__ - DWORD bufferSize = 65535; - ZeroTier::String userDefinedPath; - bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); - if (bufferSize) - return userDefinedPath; + DWORD bufferSize = 65535; + ZeroTier::String userDefinedPath; + bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); + if (bufferSize) + return userDefinedPath; #else - if (const char *userDefinedPath = getenv("ZEROTIER_HOME")) - return String(userDefinedPath); + if (const char* userDefinedPath = getenv("ZEROTIER_HOME")) + return String(userDefinedPath); #endif - // Finally, resort to using default paths if no user-defined path was provided + // Finally, resort to using default paths if no user-defined path was provided #ifdef __UNIX_LIKE__ #ifdef __APPLE__ - // /Library/... on Apple - return ZeroTier::String("/Library/Application Support/ZeroTier"); + // /Library/... on Apple + return ZeroTier::String("/Library/Application Support/ZeroTier"); #else #ifdef __BSD__ - // BSD likes /var/db instead of /var/lib - return ZeroTier::String("/var/db/zerotier"); + // BSD likes /var/db instead of /var/lib + return ZeroTier::String("/var/db/zerotier"); #else - // Use /var/lib for Linux and other *nix - return ZeroTier::String("/var/lib/zerotier"); + // Use /var/lib for Linux and other *nix + return ZeroTier::String("/var/lib/zerotier"); #endif #endif -#else // not __UNIX_LIKE__ +#else // not __UNIX_LIKE__ #ifdef __WINDOWS__ - // Look up app data folder on Windows, e.g. C:\ProgramData\... - char buf[16384]; - if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_APPDATA,NULL,0,buf))) { - ZeroTier::String tmp(buf); - tmp.append("\\ZeroTier"); - return tmp; - } else { - return ZeroTier::String("C:\\ZeroTier"); - } + // Look up app data folder on Windows, e.g. C:\ProgramData\... + char buf[16384]; + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf))) { + ZeroTier::String tmp(buf); + tmp.append("\\ZeroTier"); + return tmp; + } + else { + return ZeroTier::String("C:\\ZeroTier"); + } #else - return (ZeroTier::String(ZT_PATH_SEPARATOR_S) + "ZeroTier"); // UNKNOWN PLATFORM + return (ZeroTier::String(ZT_PATH_SEPARATOR_S) + "ZeroTier"); // UNKNOWN PLATFORM #endif -#endif // __UNIX_LIKE__ or not... +#endif // __UNIX_LIKE__ or not... } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index df3491d5e..b241c9d76 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -21,15 +21,15 @@ #include #ifndef __WINDOWS__ -#include -#include -#include #include +#include +#include +#include #endif #ifdef __APPLE__ -#include #include +#include #include #endif @@ -38,228 +38,230 @@ namespace ZeroTier { /** * Miscellaneous utility functions and global constants */ -class OSUtils -{ -private: +class OSUtils { + private: #ifdef __APPLE__ - static clock_serv_t s_machRealtimeClock; - static clock_serv_t s_machMonotonicClock; + static clock_serv_t s_machRealtimeClock; + static clock_serv_t s_machMonotonicClock; #endif -public: - /** - * Variant of snprintf that is portable and throws an exception - * - * This just wraps the local implementation whatever it's called, while - * performing a few other checks and adding exceptions for overflow. - * - * @param buf Buffer to write to - * @param len Length of buffer in bytes - * @param fmt Format string - * @param ... Format arguments - * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) - */ - static unsigned int ztsnprintf(char *buf,unsigned int len,const char *fmt,...); + public: + /** + * Variant of snprintf that is portable and throws an exception + * + * This just wraps the local implementation whatever it's called, while + * performing a few other checks and adding exceptions for overflow. + * + * @param buf Buffer to write to + * @param len Length of buffer in bytes + * @param fmt Format string + * @param ... Format arguments + * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) + */ + static unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...); #ifdef __UNIX_LIKE__ - /** - * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path - * - * This can be called after fork() and prior to exec() to suppress output - * from a subprocess, such as auto-update. - * - * @param stdoutPath Path to file to use for stdout - * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) - * @return True on success - */ - static bool redirectUnixOutputs(const char *stdoutPath,const char *stderrPath = nullptr); -#endif // __UNIX_LIKE__ + /** + * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path + * + * This can be called after fork() and prior to exec() to suppress output + * from a subprocess, such as auto-update. + * + * @param stdoutPath Path to file to use for stdout + * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) + * @return True on success + */ + static bool redirectUnixOutputs(const char* stdoutPath, const char* stderrPath = nullptr); +#endif // __UNIX_LIKE__ - /** - * Delete a file - * - * @param path Path to delete - * @return True if delete was successful - */ - static ZT_INLINE bool rm(const char *path) - { + /** + * Delete a file + * + * @param path Path to delete + * @return True if delete was successful + */ + static ZT_INLINE bool rm(const char* path) + { #ifdef __WINDOWS__ - return (DeleteFileA(path) != FALSE); + return (DeleteFileA(path) != FALSE); #else - return (unlink(path) == 0); + return (unlink(path) == 0); #endif - } + } - static ZT_INLINE bool mkdir(const char *path) - { + static ZT_INLINE bool mkdir(const char* path) + { #ifdef __WINDOWS__ - if (::PathIsDirectoryA(path)) - return true; - return (::CreateDirectoryA(path,NULL) == TRUE); + if (::PathIsDirectoryA(path)) + return true; + return (::CreateDirectoryA(path, NULL) == TRUE); #else - if (::mkdir(path,0755) != 0) - return (errno == EEXIST); - return true; + if (::mkdir(path, 0755) != 0) + return (errno == EEXIST); + return true; #endif - } + } - static ZT_INLINE bool rename(const char *o,const char *n) - { + static ZT_INLINE bool rename(const char* o, const char* n) + { #ifdef __WINDOWS__ - DeleteFileA(n); - return (::rename(o,n) == 0); + DeleteFileA(n); + return (::rename(o, n) == 0); #else - return (::rename(o,n) == 0); + return (::rename(o, n) == 0); #endif - } + } - /** - * List a directory's contents - * - * @param path Path to list - * @param includeDirectories If true, include directories as well as files - * @return Names of files in directory (without path prepended) - */ - static ZeroTier::Vector listDirectory(const char *path,bool includeDirectories = false); + /** + * List a directory's contents + * + * @param path Path to list + * @param includeDirectories If true, include directories as well as files + * @return Names of files in directory (without path prepended) + */ + static ZeroTier::Vector listDirectory(const char* path, bool includeDirectories = false); - /** - * Delete a directory and all its files and subdirectories recursively - * - * @param path Path to delete - * @return True on success - */ - static bool rmDashRf(const char *path); + /** + * Delete a directory and all its files and subdirectories recursively + * + * @param path Path to delete + * @return True on success + */ + static bool rmDashRf(const char* path); - /** - * Set modes on a file to something secure - * - * This locks a file so that only the owner can access it. What it actually - * does varies by platform. - * - * @param path Path to lock - * @param isDir True if this is a directory - */ - static void lockDownFile(const char *path,bool isDir); + /** + * Set modes on a file to something secure + * + * This locks a file so that only the owner can access it. What it actually + * does varies by platform. + * + * @param path Path to lock + * @param isDir True if this is a directory + */ + static void lockDownFile(const char* path, bool isDir); - /** - * @param path Path to check - * @param followLinks Follow links (on platforms with that concept) - * @return True if file or directory exists at path location - */ - static bool fileExists(const char *path,bool followLinks = true); + /** + * @param path Path to check + * @param followLinks Follow links (on platforms with that concept) + * @return True if file or directory exists at path location + */ + static bool fileExists(const char* path, bool followLinks = true); - /** - * @return Current time in milliseconds since epoch - */ - static ZT_INLINE int64_t now() - { + /** + * @return Current time in milliseconds since epoch + */ + static ZT_INLINE int64_t now() + { #ifdef __WINDOWS__ - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return (((LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32)) / 10000LL) - 116444736000000000LL; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return (((LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32)) / 10000LL) - 116444736000000000LL; #else #ifdef __LINUX__ - timespec ts; + timespec ts; #ifdef CLOCK_REALTIME_COARSE - clock_gettime(CLOCK_REALTIME_COARSE,&ts); + clock_gettime(CLOCK_REALTIME_COARSE, &ts); #else - clock_gettime(CLOCK_REALTIME,&ts); + clock_gettime(CLOCK_REALTIME, &ts); #endif - return ( (1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000)) ); + return ((1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000))); #else #ifdef __APPLE__ - mach_timespec_t mts; - clock_get_time(s_machRealtimeClock,&mts); - return ( (1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000)) ); + mach_timespec_t mts; + clock_get_time(s_machRealtimeClock, &mts); + return ((1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000))); #else - timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); + timeval tv; + gettimeofday(&tv, (struct timezone*)0); + return ((1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000)); #endif #endif #endif - }; + }; - /** - * Get monotonic time since some point in the past - * - * On some systems this may fall back to the same return value as now(), but - * if a monotonic (not affected by time changes) source is available it will - * be used. - * - * @return Current monotonic time in milliseconds (usually since system boot, but origin point is undefined) - */ - static ZT_INLINE int64_t now_monotonic() - { + /** + * Get monotonic time since some point in the past + * + * On some systems this may fall back to the same return value as now(), but + * if a monotonic (not affected by time changes) source is available it will + * be used. + * + * @return Current monotonic time in milliseconds (usually since system boot, but origin point is undefined) + */ + static ZT_INLINE int64_t now_monotonic() + { #ifdef __WINDOWS__ - return (int64_t)GetTickCount64(); + return (int64_t)GetTickCount64(); #else #ifdef __LINUX__ - timespec ts; - clock_gettime(CLOCK_BOOTTIME,&ts); - return ( (1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000)) ); + timespec ts; + clock_gettime(CLOCK_BOOTTIME, &ts); + return ((1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000))); #else #ifdef __APPLE__ - mach_timespec_t mts; - clock_get_time(s_machMonotonicClock,&mts); - return ( (1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000)) ); + mach_timespec_t mts; + clock_get_time(s_machMonotonicClock, &mts); + return ((1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000))); #else - timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); + timeval tv; + gettimeofday(&tv, (struct timezone*)0); + return ((1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000)); #endif #endif #endif - }; + }; - /** - * Read the full contents of a file into a string buffer - * - * The buffer isn't cleared, so if it already contains data the file's data will - * be appended. - * - * @param path Path of file to read - * @param buf Buffer to fill - * @return True if open and read successful - */ - static bool readFile(const char *path,ZeroTier::String &buf); + /** + * Read the full contents of a file into a string buffer + * + * The buffer isn't cleared, so if it already contains data the file's data will + * be appended. + * + * @param path Path of file to read + * @param buf Buffer to fill + * @return True if open and read successful + */ + static bool readFile(const char* path, ZeroTier::String& buf); - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param buf Buffer containing data - * @param len Length of buffer - * @return True if entire file was successfully written - */ - static bool writeFile(const char *path,const void *buf,unsigned int len); + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param buf Buffer containing data + * @param len Length of buffer + * @return True if entire file was successfully written + */ + static bool writeFile(const char* path, const void* buf, unsigned int len); - /** - * Split a string by delimiter, with optional escape and quote characters - * - * @param s String to split - * @param sep One or more separators - * @param esc Zero or more escape characters - * @param quot Zero or more quote characters - * @return Vector of tokens - */ - static ZeroTier::Vector split(const char *s,const char *sep,const char *esc,const char *quot); + /** + * Split a string by delimiter, with optional escape and quote characters + * + * @param s String to split + * @param sep One or more separators + * @param esc Zero or more escape characters + * @param quot Zero or more quote characters + * @return Vector of tokens + */ + static ZeroTier::Vector split(const char* s, const char* sep, const char* esc, const char* quot); - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param s Data to write - * @return True if entire file was successfully written - */ - static ZT_INLINE bool writeFile(const char *path,const ZeroTier::String &s) { return writeFile(path,s.data(),(unsigned int)s.length()); } + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param s Data to write + * @return True if entire file was successfully written + */ + static ZT_INLINE bool writeFile(const char* path, const ZeroTier::String& s) + { + return writeFile(path, s.data(), (unsigned int)s.length()); + } - /** - * @return Platform default ZeroTier One home path - */ - static ZeroTier::String platformDefaultHomePath(); + /** + * @return Platform default ZeroTier One home path + */ + static ZeroTier::String platformDefaultHomePath(); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 0f8ffa58b..30d9f70de 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -14,179 +14,188 @@ #ifndef ZT_THREAD_HPP #define ZT_THREAD_HPP -#include - #include "../core/Constants.hpp" +#include + #ifdef __WINDOWS__ +#include "../core/Mutex.hpp" + #include #include #include -#include "../core/Mutex.hpp" - namespace ZeroTier { -template -static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) +template static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) { - try { - ((C *)lpParam)->threadMain(); - } catch ( ... ) {} - return 0; + try { + ((C*)lpParam)->threadMain(); + } + catch (...) { + } + return 0; } -class Thread -{ -public: - Thread() - { - _th = NULL; - _tid = 0; - } +class Thread { + public: + Thread() + { + _th = NULL; + _tid = 0; + } - template - static inline Thread start(C *instance) - { - Thread t; - t._th = CreateThread(NULL,0,&___zt_threadMain,(LPVOID)instance,0,&t._tid); - if (t._th == NULL) - throw std::runtime_error("CreateThread() failed"); - return t; - } + template static inline Thread start(C* instance) + { + Thread t; + t._th = CreateThread(NULL, 0, &___zt_threadMain, (LPVOID)instance, 0, &t._tid); + if (t._th == NULL) + throw std::runtime_error("CreateThread() failed"); + return t; + } - static inline void join(const Thread &t) - { - if (t._th != NULL) { - for(;;) { - DWORD ec = STILL_ACTIVE; - GetExitCodeThread(t._th,&ec); - if (ec == STILL_ACTIVE) - WaitForSingleObject(t._th,1000); - else break; - } - } - } + static inline void join(const Thread& t) + { + if (t._th != NULL) { + for (;;) { + DWORD ec = STILL_ACTIVE; + GetExitCodeThread(t._th, &ec); + if (ec == STILL_ACTIVE) + WaitForSingleObject(t._th, 1000); + else + break; + } + } + } - static inline void sleep(unsigned long ms) - { - Sleep((DWORD)ms); - } + static inline void sleep(unsigned long ms) + { + Sleep((DWORD)ms); + } - // Not available on *nix platforms - static inline void cancelIO(const Thread &t) - { -#if !defined(__MINGW32__) && !defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2 - if (t._th != NULL) - CancelSynchronousIo(t._th); + // Not available on *nix platforms + static inline void cancelIO(const Thread& t) + { +#if ! defined(__MINGW32__) && ! defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2 + if (t._th != NULL) + CancelSynchronousIo(t._th); #endif - } + } - inline operator bool() const { return (_th != NULL); } + inline operator bool() const + { + return (_th != NULL); + } -private: - HANDLE _th; - DWORD _tid; + private: + HANDLE _th; + DWORD _tid; }; -} // namespace ZeroTier +} // namespace ZeroTier #else +#include #include #include #include -#include #include namespace ZeroTier { -template -static void *___zt_threadMain(void *instance) +template static void* ___zt_threadMain(void* instance) { - try { - ((C *)instance)->threadMain(); - } catch ( ... ) {} - return (void *)0; + try { + ((C*)instance)->threadMain(); + } + catch (...) { + } + return (void*)0; } /** * A thread identifier, and static methods to start and join threads */ -class Thread -{ -public: - Thread() - { - memset(this,0,sizeof(Thread)); - } +class Thread { + public: + Thread() + { + memset(this, 0, sizeof(Thread)); + } - Thread(const Thread &t) - { - memcpy(this,&t,sizeof(Thread)); - } + Thread(const Thread& t) + { + memcpy(this, &t, sizeof(Thread)); + } - inline Thread &operator=(const Thread &t) - { - memcpy(this,&t,sizeof(Thread)); - return *this; - } + inline Thread& operator=(const Thread& t) + { + memcpy(this, &t, sizeof(Thread)); + return *this; + } - /** - * Start a new thread - * - * @param instance Instance whose threadMain() method gets called by new thread - * @return Thread identifier - * @throws std::runtime_error Unable to create thread - * @tparam C Class containing threadMain() - */ - template - static inline Thread start(C *instance) - { - Thread t; - pthread_attr_t tattr; - pthread_attr_init(&tattr); - // This corrects for systems with abnormally small defaults (musl) and also - // shrinks the stack on systems with large defaults to save a bit of memory. - pthread_attr_setstacksize(&tattr,1048576); - if (pthread_create(&t._tid,&tattr,&___zt_threadMain,instance)) { - pthread_attr_destroy(&tattr); - throw std::runtime_error("pthread_create() failed, unable to create thread"); - } else { - t._started = true; - pthread_attr_destroy(&tattr); - } - return t; - } + /** + * Start a new thread + * + * @param instance Instance whose threadMain() method gets called by new thread + * @return Thread identifier + * @throws std::runtime_error Unable to create thread + * @tparam C Class containing threadMain() + */ + template static inline Thread start(C* instance) + { + Thread t; + pthread_attr_t tattr; + pthread_attr_init(&tattr); + // This corrects for systems with abnormally small defaults (musl) and also + // shrinks the stack on systems with large defaults to save a bit of memory. + pthread_attr_setstacksize(&tattr, 1048576); + if (pthread_create(&t._tid, &tattr, &___zt_threadMain, instance)) { + pthread_attr_destroy(&tattr); + throw std::runtime_error("pthread_create() failed, unable to create thread"); + } + else { + t._started = true; + pthread_attr_destroy(&tattr); + } + return t; + } - /** - * Join to a thread, waiting for it to terminate (does nothing on null Thread values) - * - * @param t Thread to join - */ - static inline void join(const Thread &t) - { - if (t._started) - pthread_join(t._tid,(void **)0); - } + /** + * Join to a thread, waiting for it to terminate (does nothing on null Thread values) + * + * @param t Thread to join + */ + static inline void join(const Thread& t) + { + if (t._started) + pthread_join(t._tid, (void**)0); + } - /** - * Sleep the current thread - * - * @param ms Number of milliseconds to sleep - */ - static inline void sleep(unsigned long ms) { usleep(ms * 1000); } + /** + * Sleep the current thread + * + * @param ms Number of milliseconds to sleep + */ + static inline void sleep(unsigned long ms) + { + usleep(ms * 1000); + } - inline operator bool() const { return (_started); } + inline operator bool() const + { + return (_started); + } -private: - pthread_t _tid; - volatile bool _started; + private: + pthread_t _tid; + volatile bool _started; }; -} // namespace ZeroTier +} // namespace ZeroTier -#endif // __WINDOWS__ / !__WINDOWS__ +#endif // __WINDOWS__ / !__WINDOWS__ #endif diff --git a/osdep/rust-osdep.cpp b/osdep/rust-osdep.cpp index 15dd002fc..0f8d08f4e 100644 --- a/osdep/rust-osdep.cpp +++ b/osdep/rust-osdep.cpp @@ -14,27 +14,27 @@ /* Fix for an issue with this structure not being present on MacOS */ #ifdef __APPLE__ struct prf_ra { - unsigned char onlink : 1; - unsigned char autonomous : 1; - unsigned char reserved : 6; + unsigned char onlink : 1; + unsigned char autonomous : 1; + unsigned char reserved : 6; } prf_ra; #endif -#include "../core/Constants.hpp" -#include "../core/Mutex.hpp" -#include "../core/Containers.hpp" -#include "../core/SHA512.hpp" -#include "../core/AES.hpp" -#include "OSUtils.hpp" - #include "rust-osdep.h" +#include "../core/AES.hpp" +#include "../core/Constants.hpp" +#include "../core/Containers.hpp" +#include "../core/Mutex.hpp" +#include "../core/SHA512.hpp" +#include "OSUtils.hpp" + #ifdef __APPLE__ #ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ +#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ #endif #ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ +#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ #endif #endif @@ -53,102 +53,117 @@ const unsigned long c_SIOCAUTOCONF_START = SIOCAUTOCONF_START; const unsigned long c_SIOCAUTOCONF_STOP = SIOCAUTOCONF_STOP; #endif -const char *platformDefaultHomePath() +const char* platformDefaultHomePath() { - static ZeroTier::Mutex s_lock; - static ZeroTier::String s_homePath; + static ZeroTier::Mutex s_lock; + static ZeroTier::String s_homePath; - ZeroTier::Mutex::Lock l(s_lock); - if (s_homePath.empty()) { + ZeroTier::Mutex::Lock l(s_lock); + if (s_homePath.empty()) { #ifdef __QNAP__ - char *cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; - char buf[128]; - FILE *fp; - if ((fp = popen(cmd, "r")) == NULL) { - printf("Error opening pipe!\n"); - return NULL; - } - while (fgets(buf, 128, fp) != NULL) { } - if(pclose(fp)) { - printf("Command not found or exited with error status\n"); - return NULL; - } - String homeDir = String(buf); - homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end()); - s_homePath = homeDir; + char* cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; + char buf[128]; + FILE* fp; + if ((fp = popen(cmd, "r")) == NULL) { + printf("Error opening pipe!\n"); + return NULL; + } + while (fgets(buf, 128, fp) != NULL) {} + if (pclose(fp)) { + printf("Command not found or exited with error status\n"); + return NULL; + } + String homeDir = String(buf); + homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end()); + s_homePath = homeDir; #else #ifdef __WINDOWS__ - DWORD bufferSize = 65535; - ZeroTier::String userDefinedPath; - bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); - if (bufferSize) { - s_homePath = userDefinedPath; - } else { - char buf[16384]; - if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_APPDATA,NULL,0,buf))) { - ZeroTier::String tmp(buf); - tmp.append("\\ZeroTier"); - s_homePath = tmp; - } else { - s_homePath = "C:\\ZeroTier"; - } - } + DWORD bufferSize = 65535; + ZeroTier::String userDefinedPath; + bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); + if (bufferSize) { + s_homePath = userDefinedPath; + } + else { + char buf[16384]; + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf))) { + ZeroTier::String tmp(buf); + tmp.append("\\ZeroTier"); + s_homePath = tmp; + } + else { + s_homePath = "C:\\ZeroTier"; + } + } #else - if (const char *userDefinedPath = getenv("ZEROTIER_HOME")) { - s_homePath = userDefinedPath; - } else { + if (const char* userDefinedPath = getenv("ZEROTIER_HOME")) { + s_homePath = userDefinedPath; + } + else { #ifdef __APPLE__ - s_homePath = "/Library/Application Support/ZeroTier"; + s_homePath = "/Library/Application Support/ZeroTier"; #else #ifdef __BSD__ - s_homePath = "/var/db/zerotier"; + s_homePath = "/var/db/zerotier"; #else - s_homePath = "/var/lib/zerotier"; -#endif // __BSD__ or not -#endif // __APPLE__ or not - } + s_homePath = "/var/lib/zerotier"; +#endif // __BSD__ or not +#endif // __APPLE__ or not + } -#endif // __WINDOWS__ or not +#endif // __WINDOWS__ or not -#endif // __QNAP__ or not +#endif // __QNAP__ or not - if (s_homePath.empty()) - s_homePath = "." ZT_PATH_SEPARATOR_S; - } + if (s_homePath.empty()) + s_homePath = "." ZT_PATH_SEPARATOR_S; + } - return s_homePath.c_str(); + return s_homePath.c_str(); } int64_t msSinceEpoch() -{ return ZeroTier::OSUtils::now(); } +{ + return ZeroTier::OSUtils::now(); +} int64_t msMonotonic() -{ return ZeroTier::OSUtils::now_monotonic(); } +{ + return ZeroTier::OSUtils::now_monotonic(); +} -void lockDownFile(const char *path, int isDir) -{ ZeroTier::OSUtils::lockDownFile(path, isDir != 0); } +void lockDownFile(const char* path, int isDir) +{ + ZeroTier::OSUtils::lockDownFile(path, isDir != 0); +} -void getSecureRandom(void *buf, unsigned int len) -{ ZeroTier::Utils::getSecureRandom(buf, len); } +void getSecureRandom(void* buf, unsigned int len) +{ + ZeroTier::Utils::getSecureRandom(buf, len); +} static ZT_INLINE ZeroTier::AES _makeHttpAuthCipher() noexcept { - uint8_t key[32]; - ZeroTier::Utils::getSecureRandom(key, 32); - return ZeroTier::AES(key); + uint8_t key[32]; + ZeroTier::Utils::getSecureRandom(key, 32); + return ZeroTier::AES(key); } static const ZeroTier::AES HTTP_AUTH_CIPHER = _makeHttpAuthCipher(); -void encryptHttpAuthNonce(void *block) -{ HTTP_AUTH_CIPHER.encrypt(block, block); } +void encryptHttpAuthNonce(void* block) +{ + HTTP_AUTH_CIPHER.encrypt(block, block); +} -void decryptHttpAuthNonce(void *block) -{ HTTP_AUTH_CIPHER.decrypt(block, block); } +void decryptHttpAuthNonce(void* block) +{ + HTTP_AUTH_CIPHER.decrypt(block, block); +} } /* extern "C" */ diff --git a/osdep/rust-osdep.h b/osdep/rust-osdep.h index fb369d7f3..2547dd0e8 100644 --- a/osdep/rust-osdep.h +++ b/osdep/rust-osdep.h @@ -18,38 +18,36 @@ /********************************************************************************************************************/ #ifdef __APPLE__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include -#include #include #include #include #include #include +#include +#include +#include +#include #include #include -#include -#include -#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif @@ -76,24 +74,24 @@ extern const unsigned long c_SIOCAUTOCONF_STOP; /********************************************************************************************************************/ #if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include -#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif /* __linux__ */ /********************************************************************************************************************/ @@ -103,27 +101,28 @@ extern "C" { #endif // Get the default home path for this platform. -extern const char *platformDefaultHomePath(); +extern const char* platformDefaultHomePath(); // This ms-since-epoch function may be faster than the one in Rust's stdlib. extern int64_t msSinceEpoch(); -// This is the number of milliseconds since some time in the past, unaffected by the clock (or msSinceEpoch() if not supported by host). +// This is the number of milliseconds since some time in the past, unaffected by the clock (or msSinceEpoch() if not +// supported by host). extern int64_t msMonotonic(); // Rust glue to C code to lock down a file, which is simple on Unix-like OSes // and horrible on Windows. -extern void lockDownFile(const char *path, int isDir); +extern void lockDownFile(const char* path, int isDir); // Rust glue to ZeroTier's secure random PRNG. -extern void getSecureRandom(void *buf, unsigned int len); +extern void getSecureRandom(void* buf, unsigned int len); // These AES encrypt and decrypt a single block using a key that is randomly // generated at process init and never exported. It's used to generate HTTP // digest authentication tokens that can just be decrypted to get and check // a timestamp to prevent replay attacks. -extern void encryptHttpAuthNonce(void *block); -extern void decryptHttpAuthNonce(void *block); +extern void encryptHttpAuthNonce(void* block); +extern void decryptHttpAuthNonce(void* block); #ifdef __cplusplus }