Speed up V1 identity verification a little, and add some comments.

This commit is contained in:
Adam Ierymenko 2020-02-27 09:43:58 -08:00
parent c5bd21a23e
commit fbfa99fac5
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
6 changed files with 193 additions and 114 deletions

View file

@ -338,8 +338,11 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info) void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info)
{ {
for(auto ab=nw->activeBridgeMembers.begin();ab!=nw->activeBridgeMembers.end();++ab) for(auto ab=nw->activeBridgeMembers.begin();ab!=nw->activeBridgeMembers.end();++ab) {
info.activeBridges.push_back(Address(*ab)); const Address aba(*ab);
if (nw->authorizedMembers.count(aba) != 0)
info.activeBridges.push_back(aba);
}
std::sort(info.activeBridges.begin(),info.activeBridges.end()); std::sort(info.activeBridges.begin(),info.activeBridges.end());
for(auto ip=nw->allocatedIps.begin();ip!=nw->allocatedIps.end();++ip) for(auto ip=nw->allocatedIps.begin();ip!=nw->allocatedIps.end();++ip)
info.allocatedIps.push_back(*ip); info.allocatedIps.push_back(*ip);

View file

@ -89,11 +89,13 @@ bool Identity::generate(const Type t)
switch(t) { switch(t) {
case C25519: { 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]; uint8_t digest[64];
char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY]; char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
do { do {
C25519::generateSatisfying(_v0_identity_generate_cond(digest,genmem),_pub.c25519,_priv.c25519); C25519::generateSatisfying(_v0_identity_generate_cond(digest,genmem),_pub.c25519,_priv.c25519);
_address.setTo(digest + 59); // last 5 bytes are address _address.setTo(digest + 59);
} while (_address.isReserved()); } while (_address.isReserved());
delete[] genmem; delete[] genmem;
_computeHash(); _computeHash();
@ -101,9 +103,15 @@ bool Identity::generate(const Type t)
case P384: { case P384: {
for(;;) { for(;;) {
// Generate C25519, Ed25519, and NIST P-384 key pairs.
C25519::generate(_pub.c25519,_priv.c25519); C25519::generate(_pub.c25519,_priv.c25519);
ECC384GenerateKey(_pub.p384,_priv.p384); ECC384GenerateKey(_pub.p384,_priv.p384);
// Execute the MIMC52 verifiable delay function, resulting a near constant time delay relative
// to the speed of the current CPU. This result is incorporated into the final hash.
Utils::storeBigEndian(_pub.t1mimc52,mimc52Delay(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE)); Utils::storeBigEndian(_pub.t1mimc52,mimc52Delay(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE));
// Compute SHA384 fingerprint hash of keys and MIMC output and generate address directly from it.
_computeHash(); _computeHash();
_address.setTo(_fp.data()); _address.setTo(_fp.data());
if (!_address.isReserved()) if (!_address.isReserved())
@ -118,21 +126,19 @@ bool Identity::generate(const Type t)
return true; return true;
} }
bool Identity::locallyValidate() const bool Identity::locallyValidate() const noexcept
{ {
if ((_address.isReserved())||(!_address)) try {
return false; if ((!_address.isReserved()) && (_address)) {
switch (_type) { switch (_type) {
case C25519: case C25519: {
try {
uint8_t digest[64]; uint8_t digest[64];
char *genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY]; char *genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem); _computeMemoryHardHash(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
delete [] genmem; delete[] genmem;
return ((_address == Address(digest + 59))&&(digest[0] < 17)); return ((_address == Address(digest + 59)) && (digest[0] < 17));
} catch ( ... ) {} }
break;
case P384: case P384:
if (_address == Address(_fp.data())) { if (_address == Address(_fp.data())) {
@ -140,13 +146,16 @@ bool Identity::locallyValidate() const
// that can indicate that more work than the required minimum has been performed. Right now this is never done // that can indicate that more work than the required minimum has been performed. Right now this is never done
// but it could have some use in the future. There is no harm in doing it, and we'll accept any round count // but it could have some use in the future. There is no harm in doing it, and we'll accept any round count
// that is at least ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE. // that is at least ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE.
const unsigned long rounds = ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE * ((unsigned long)_pub.t1mimc52[0] + 1U); unsigned long rounds = (((unsigned long)_pub.t1mimc52[0] & 15U) + 1U); // max: 16 * ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE
if (mimc52Verify(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),rounds,Utils::loadBigEndian<uint64_t>(_pub.t1mimc52))) rounds *= ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE;
return true; return mimc52Verify(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),rounds,Utils::loadBigEndian<uint64_t>(_pub.t1mimc52));
} else {
return false;
} }
break;
} }
}
} catch ( ... ) {}
return false; return false;
} }

View file

@ -105,7 +105,7 @@ public:
* *
* @return True if validation check passes * @return True if validation check passes
*/ */
bool locallyValidate() const; bool locallyValidate() const noexcept;
/** /**
* @return True if this identity contains a private key * @return True if this identity contains a private key

File diff suppressed because one or more lines are too long

View file

@ -180,8 +180,8 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
#define IDENTITY_V0_KNOWN_GOOD_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e" #define IDENTITY_V0_KNOWN_GOOD_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
#define IDENTITY_V0_KNOWN_BAD_0 "9e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e" #define IDENTITY_V0_KNOWN_BAD_0 "9e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
#define IDENTITY_V1_KNOWN_GOOD_0 "237ce8d8e2:1:5w3rj6am3sa7f5vtwm535iswob6ngmkpdidijz5ormqrfwkj55lhwyyszruu4rkbjycmlxzzoiuwtyw5s2mybknqx5j2cwxnaflqbwycoio2hqzcro5afrpcncnxlemzs6bt5linlib5flsej3f3r3bbzclxk733ei7tdrtm5uruiwpmyi4vgaafze42sx6hpe:mwjavgvhxz75ow2fhgq3zu4qfou5kce4wzegpjjd6545fpjnhjxb26e5unuutv7k3c6sm6umpyvatgpufwehi4wqmyudvq724h2klbiem6txs2h5iit5crgg3e6se5xeomuqhircv7zhkylrtnlgh57il742pwkrdgt4lz5fstetmiw7y3rq" #define IDENTITY_V1_KNOWN_GOOD_0 "12a4e65422:1:norcnqlkhl2ly6aljrguqntd7bfwdpfpgse32gy2nonhrninfyfxbz4qyj4i7jm2jn6c5hnr6fe3j7a556w5irhtmz77ajdkw6ge2nadlwczld5yak4mhdj46bcwvgzpu3evsfbx44psgughwwgp7rl5ju2gcw4mil5csvd3dp6itwqksyzf6aake3fpn5seo4:ds3mdnqdnbveqlyqq446if3tdilsva4fpsaqahqysavvbv23j655yfahihupezaic56uqrk2dbaamdj2fzmyzulhraux2daj3p6hnxyrhbwugu2ukuqi4eucdck4eczjqcgmv33w65nyxkm3gvhahmoc3zwt2nqmexcdsxlqccexfcpvinuq"
#define IDENTITY_V1_KNOWN_BAD_0 "238ce8d8e2:1:5w3rj6am3sa7f5vtwm535iswob6ngmkpdidijz5ormqrfwkj55lhwyyszruu4rkbjycmlxzzoiuwtyw5s2mybknqx5j2cwxnaflqbwycoio2hqzcro5afrpcncnxlemzs6bt5linlib5flsej3f3r3bbzclxk733ei7tdrtm5uruiwpmyi4vgaafze42sx6hpe:mwjavgvhxz75ow2fhgq3zu4qfou5kce4wzegpjjd6545fpjnhjxb26e5unuutv7k3c6sm6umpyvatgpufwehi4wqmyudvq724h2klbiem6txs2h5iit5crgg3e6se5xeomuqhircv7zhkylrtnlgh57il742pwkrdgt4lz5fstetmiw7y3rq" #define IDENTITY_V1_KNOWN_BAD_0 "22a4e65422:1:norcnqlkhl2ly6aljrguqntd7bfwdpfpgse32gy2nonhrninfyfxbz4qyj4i7jm2jn6c5hnr6fe3j7a556w5irhtmz77ajdkw6ge2nadlwczld5yak4mhdj46bcwvgzpu3evsfbx44psgughwwgp7rl5ju2gcw4mil5csvd3dp6itwqksyzf6aake3fpn5seo4:ds3mdnqdnbveqlyqq446if3tdilsva4fpsaqahqysavvbv23j655yfahihupezaic56uqrk2dbaamdj2fzmyzulhraux2daj3p6hnxyrhbwugu2ukuqi4eucdck4eczjqcgmv33w65nyxkm3gvhahmoc3zwt2nqmexcdsxlqccexfcpvinuq"
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
@ -639,7 +639,7 @@ extern "C" const char *ZTT_crypto()
{ {
ZT_T_PRINTF("[crypto] Testing MIMC52 VDF... "); ZT_T_PRINTF("[crypto] Testing MIMC52 VDF... ");
const uint64_t proof = mimc52Delay("testing",7,1000); const uint64_t proof = mimc52Delay("testing",7,1000);
if ((!mimc52Verify("testing",7,1000,proof))||(proof != 0x0007a1a0a1b0fe32)) { if ((!mimc52Verify("testing",7,1000,proof))||(proof != 0x000b501115c73369)) {
ZT_T_PRINTF("FAILED (%.16llx)" ZT_EOL_S,proof); ZT_T_PRINTF("FAILED (%.16llx)" ZT_EOL_S,proof);
return "MIMC52 failed simple delay/verify test"; return "MIMC52 failed simple delay/verify test";
} }

View file

@ -423,14 +423,14 @@ static ZT_ALWAYS_INLINE uint64_t swapBytes(uint64_t n) noexcept
#endif #endif
#else #else
return ( return (
((n & 0x00000000000000FFULL) << 56) | ((n & 0x00000000000000ffULL) << 56) |
((n & 0x000000000000FF00ULL) << 40) | ((n & 0x000000000000ff00ULL) << 40) |
((n & 0x0000000000FF0000ULL) << 24) | ((n & 0x0000000000ff0000ULL) << 24) |
((n & 0x00000000FF000000ULL) << 8) | ((n & 0x00000000ff000000ULL) << 8) |
((n & 0x000000FF00000000ULL) >> 8) | ((n & 0x000000ff00000000ULL) >> 8) |
((n & 0x0000FF0000000000ULL) >> 24) | ((n & 0x0000ff0000000000ULL) >> 24) |
((n & 0x00FF000000000000ULL) >> 40) | ((n & 0x00ff000000000000ULL) >> 40) |
((n & 0xFF00000000000000ULL) >> 56) ((n & 0xff00000000000000ULL) >> 56)
); );
#endif #endif
} }
@ -446,15 +446,32 @@ template<typename I>
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) noexcept static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
I x = (I)0; if (sizeof(I) == 8) {
for(unsigned int k=0;k<sizeof(I);++k) { return (I)(
#if __BYTE_ORDER == __LITTLE_ENDIAN ((uint64_t)reinterpret_cast<const uint8_t *>(p)[0] << 56U) |
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[(sizeof(I)-1)-k]; ((uint64_t)reinterpret_cast<const uint8_t *>(p)[1] << 48U) |
#else ((uint64_t)reinterpret_cast<const uint8_t *>(p)[2] << 40U) |
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[k]; ((uint64_t)reinterpret_cast<const uint8_t *>(p)[3] << 32U) |
#endif ((uint64_t)reinterpret_cast<const uint8_t *>(p)[4] << 24U) |
((uint64_t)reinterpret_cast<const uint8_t *>(p)[5] << 16U) |
((uint64_t)reinterpret_cast<const uint8_t *>(p)[6] << 8U) |
(uint64_t)reinterpret_cast<const uint8_t *>(p)[7]
);
} else if (sizeof(I) == 4) {
return (I)(
((uint32_t)reinterpret_cast<const uint8_t *>(p)[0] << 24U) |
((uint32_t)reinterpret_cast<const uint8_t *>(p)[1] << 16U) |
((uint32_t)reinterpret_cast<const uint8_t *>(p)[2] << 8U) |
(uint32_t)reinterpret_cast<const uint8_t *>(p)[3]
);
} else if (sizeof(I) == 2) {
return (I)(
((unsigned int)reinterpret_cast<const uint8_t *>(p)[0] << 8U) |
(unsigned int)reinterpret_cast<const uint8_t *>(p)[1]
);
} else {
return (I)reinterpret_cast<const uint8_t *>(p)[0];
} }
return x;
#else #else
return ntoh(*reinterpret_cast<const I *>(p)); return ntoh(*reinterpret_cast<const I *>(p));
#endif #endif
@ -468,15 +485,28 @@ static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) noexcept
* #param i Integer to write * #param i Integer to write
*/ */
template<typename I> template<typename I>
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i) noexcept static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) { if (sizeof(I) == 8) {
#if __BYTE_ORDER == __LITTLE_ENDIAN reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 56U);
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k]; reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 48U);
#else reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 40U);
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k]; reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 32U);
#endif reinterpret_cast<uint8_t *>(p)[4] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 24U);
reinterpret_cast<uint8_t *>(p)[5] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 16U);
reinterpret_cast<uint8_t *>(p)[6] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 8U);
reinterpret_cast<uint8_t *>(p)[7] = (uint8_t)reinterpret_cast<uint64_t>(i);
} else if (sizeof(I) == 4) {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 24U);
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 16U);
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 8U);
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)reinterpret_cast<uint32_t>(i);
} else if (sizeof(I) == 2) {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint16_t>(i) >> 8U);
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)reinterpret_cast<uint16_t>(i);
} else {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)i;
} }
#else #else
*reinterpret_cast<I *>(p) = hton(i); *reinterpret_cast<I *>(p) = hton(i);
@ -486,33 +516,42 @@ static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i) noexcept
/** /**
* Decode a little-endian value from a byte stream * Decode a little-endian value from a byte stream
* *
* @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t) * @tparam I Type to decode
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template<typename I> template<typename I>
static ZT_ALWAYS_INLINE I loadLittleEndian(const void *const p) noexcept static ZT_ALWAYS_INLINE I loadLittleEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
I x = (I)0; if (sizeof(I) == 8) {
for(unsigned int k=0;k<sizeof(I);++k) { return (I)(
#if __BYTE_ORDER == __LITTLE_ENDIAN (uint64_t)reinterpret_cast<const uint8_t *>(p)[0] |
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[k]; ((uint64_t)reinterpret_cast<const uint8_t *>(p)[1] << 8U) |
#else ((uint64_t)reinterpret_cast<const uint8_t *>(p)[2] << 16U) |
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[(sizeof(I)-1)-k]; ((uint64_t)reinterpret_cast<const uint8_t *>(p)[3] << 24U) |
#endif ((uint64_t)reinterpret_cast<const uint8_t *>(p)[4] << 32U) |
((uint64_t)reinterpret_cast<const uint8_t *>(p)[5] << 40U) |
((uint64_t)reinterpret_cast<const uint8_t *>(p)[6] << 48U) |
((uint64_t)reinterpret_cast<const uint8_t *>(p)[7] << 56U)
);
} else if (sizeof(I) == 4) {
return (I)(
(uint32_t)reinterpret_cast<const uint8_t *>(p)[0] |
((uint32_t)reinterpret_cast<const uint8_t *>(p)[1] << 8U) |
((uint32_t)reinterpret_cast<const uint8_t *>(p)[2] << 16U) |
((uint32_t)reinterpret_cast<const uint8_t *>(p)[3] << 24U)
);
} else if (sizeof(I) == 2) {
return (I)(
(unsigned int)reinterpret_cast<const uint8_t *>(p)[0] |
((unsigned int)reinterpret_cast<const uint8_t *>(p)[1] << 8U)
);
} else {
return (I)reinterpret_cast<const uint8_t *>(p)[0];
} }
return x;
#else #else
#if __BYTE_ORDER == __LITTLE_ENDIAN
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I *>(p);
#else
I x = (I)0;
for(unsigned int k=0;k<sizeof(I);++k) {
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[(sizeof(I)-1)-k];
}
return x;
#endif
#endif #endif
} }
@ -526,22 +565,29 @@ static ZT_ALWAYS_INLINE I loadLittleEndian(const void *const p) noexcept
template<typename I> template<typename I>
static ZT_ALWAYS_INLINE void storeLittleEndian(void *const p,const I i) noexcept static ZT_ALWAYS_INLINE void storeLittleEndian(void *const p,const I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
for(unsigned int k=0;k<sizeof(I);++k) { if (sizeof(I) == 8) {
#if __BYTE_ORDER == __LITTLE_ENDIAN reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint64_t>(i);
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k]; reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 8U);
#else reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 16U);
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k]; reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 24U);
#endif reinterpret_cast<uint8_t *>(p)[4] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 32U);
reinterpret_cast<uint8_t *>(p)[5] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 40U);
reinterpret_cast<uint8_t *>(p)[6] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 48U);
reinterpret_cast<uint8_t *>(p)[7] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 56U);
} else if (sizeof(I) == 4) {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint32_t>(i);
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 8U);
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 16U);
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 24U);
} else if (sizeof(I) == 2) {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint16_t>(i);
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint16_t>(i) >> 8U);
} else {
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)i;
} }
#else #else
#if __BYTE_ORDER == __LITTLE_ENDIAN
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I *>(p) = i;
#else
for(unsigned int k=0;k<sizeof(I);++k) {
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k];
}
#endif
#endif #endif
} }