Small fix, docs, warning removal.

This commit is contained in:
Adam Ierymenko 2020-03-16 06:14:41 -07:00
parent 1c7baa544b
commit c7f3f3add9
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3

View file

@ -32,7 +32,7 @@ namespace {
// This is the memory-intensive hash function used to compute v0 identities from v0 public keys. // This is the memory-intensive hash function used to compute v0 identities from v0 public keys.
#define ZT_V0_IDENTITY_GEN_MEMORY 2097152 #define ZT_V0_IDENTITY_GEN_MEMORY 2097152
void _computeMemoryHardHash(const void *const publicKey,unsigned int publicKeyBytes,void *const digest,void *const genmem) noexcept void identityV0ProofOfWorkFrankenhash(const void *const publicKey,unsigned int publicKeyBytes,void *const digest,void *const genmem) noexcept
{ {
// Digest publicKey[] to obtain initial digest // Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes); SHA512(digest,publicKey,publicKeyBytes);
@ -66,12 +66,12 @@ void _computeMemoryHardHash(const void *const publicKey,unsigned int publicKeyBy
s20.crypt20(digest,digest,64); s20.crypt20(digest,digest,64);
} }
} }
struct _v0_identity_generate_cond struct identityV0ProofOfWorkCriteria
{ {
ZT_INLINE _v0_identity_generate_cond(unsigned char *sb,char *gm) noexcept : digest(sb),genmem(gm) {} ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char *sb,char *gm) noexcept : digest(sb),genmem(gm) {}
ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN]) const noexcept ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN]) const noexcept
{ {
_computeMemoryHardHash(pub,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem); identityV0ProofOfWorkFrankenhash(pub,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
return (digest[0] < 17); return (digest[0] < 17);
} }
unsigned char *digest; unsigned char *digest;
@ -79,18 +79,23 @@ struct _v0_identity_generate_cond
}; };
// This is a simpler memory-intensive hash function for V1 identity generation. // This is a simpler memory-intensive hash function for V1 identity generation.
bool _v1_identity_generate_cond(const void *in,const unsigned int len) // It's not quite as intensive as the V0 frankenhash, is a little more orderly in
// its design, but remains relatively resistant to GPU acceleration due to memory
// requirements for efficient computation.
bool identityV1ProofOfWorkCriteria(const void *in,const unsigned int len)
{ {
uint64_t b[98304]; // 768 KiB uint64_t b[98304]; // 768 KiB of working memory
uint64_t polykey[4]; uint64_t polykey[4];
SHA512(b,in,len); SHA512(b,in,len);
// Poly1305 key, used in final hash at the end.
polykey[0] = b[0]; polykey[0] = b[0];
polykey[1] = b[1]; polykey[1] = b[1];
polykey[2] = b[2]; polykey[2] = b[2];
polykey[3] = b[3]; polykey[3] = b[3];
// Put bits in hash in LE byte order on BE machines.
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
b[0] = Utils::swapBytes(b[0]); b[0] = Utils::swapBytes(b[0]);
b[1] = Utils::swapBytes(b[1]); b[1] = Utils::swapBytes(b[1]);
@ -102,6 +107,11 @@ bool _v1_identity_generate_cond(const void *in,const unsigned int len)
b[7] = Utils::swapBytes(b[7]); b[7] = Utils::swapBytes(b[7]);
#endif #endif
// Memory-intensive work: fill 'b' with pseudo-random bits generated from
// a reduced-round instance of Speck128 using a CBC-like construction.
// Then sort the resulting integer array in ascending numerical order.
// The sort requires that we compute and cache the whole data set, or at
// least that this is the most efficient implementation.
Speck128<24> s16; Speck128<24> s16;
s16.initXY(b[4],b[5]); s16.initXY(b[4],b[5]);
for(unsigned long i=0;i<(98304-8);) { for(unsigned long i=0;i<(98304-8);) {
@ -130,6 +140,7 @@ bool _v1_identity_generate_cond(const void *in,const unsigned int len)
} }
std::sort(b,b + 98304); std::sort(b,b + 98304);
// Put bits in little-endian byte order if this is a BE machine.
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
for(unsigned int i=0;i<98304;i+=8) { for(unsigned int i=0;i<98304;i+=8) {
b[i] = Utils::swapBytes(b[i]); b[i] = Utils::swapBytes(b[i]);
@ -143,7 +154,14 @@ bool _v1_identity_generate_cond(const void *in,const unsigned int len)
} }
#endif #endif
// Use poly1305 to compute a very fast digest of 'b'. This doesn't have to be
// cryptographic per se, just have good hashing properties.
poly1305(b,b,sizeof(b),polykey); poly1305(b,b,sizeof(b),polykey);
// Criterion: add two 64-bit components of poly1305 hash, must be zero mod 180.
// As with the rest of this bits are used in little-endian byte order. The value
// of 180 was set empirically to result in about one second per new identity on
// one CPU core of a typical desktop or server in 2020.
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
const uint64_t finalHash = Utils::swapBytes(b[0]) + Utils::swapBytes(b[1]); const uint64_t finalHash = Utils::swapBytes(b[0]) + Utils::swapBytes(b[1]);
#else #else
@ -168,7 +186,7 @@ bool Identity::generate(const Type t)
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(identityV0ProofOfWorkCriteria(digest,genmem),_pub.c25519,_priv.c25519);
_address.setTo(digest + 59); _address.setTo(digest + 59);
} while (_address.isReserved()); } while (_address.isReserved());
delete[] genmem; delete[] genmem;
@ -182,7 +200,7 @@ v1_pow_new_keys:
C25519::generate(_pub.c25519,_priv.c25519); C25519::generate(_pub.c25519,_priv.c25519);
ECC384GenerateKey(_pub.p384,_priv.p384); ECC384GenerateKey(_pub.p384,_priv.p384);
for (;;) { for (;;) {
if (_v1_identity_generate_cond(&_pub,sizeof(_pub))) if (identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub)))
break; break;
if (++_pub.nonce == 0) // endian-ness doesn't matter, just change the nonce each time if (++_pub.nonce == 0) // endian-ness doesn't matter, just change the nonce each time
goto v1_pow_new_keys; goto v1_pow_new_keys;
@ -211,13 +229,13 @@ bool Identity::locallyValidate() const noexcept
case C25519: { case C25519: {
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); identityV0ProofOfWorkFrankenhash(_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));
} }
case P384: case P384:
return ( (_address == Address(_fp.hash())) && _v1_identity_generate_cond(&_pub,sizeof(_pub)) ); return ((_address == Address(_fp.hash())) && identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub)) );
} }
} }