mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Small fix, docs, warning removal.
This commit is contained in:
parent
1c7baa544b
commit
c7f3f3add9
1 changed files with 28 additions and 10 deletions
|
@ -32,7 +32,7 @@ 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 _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
|
||||
SHA512(digest,publicKey,publicKeyBytes);
|
||||
|
@ -66,12 +66,12 @@ void _computeMemoryHardHash(const void *const publicKey,unsigned int publicKeyBy
|
|||
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
|
||||
{
|
||||
_computeMemoryHardHash(pub,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
identityV0ProofOfWorkFrankenhash(pub,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
return (digest[0] < 17);
|
||||
}
|
||||
unsigned char *digest;
|
||||
|
@ -79,18 +79,23 @@ struct _v0_identity_generate_cond
|
|||
};
|
||||
|
||||
// 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];
|
||||
|
||||
SHA512(b,in,len);
|
||||
|
||||
// Poly1305 key, used in final hash at the end.
|
||||
polykey[0] = b[0];
|
||||
polykey[1] = b[1];
|
||||
polykey[2] = b[2];
|
||||
polykey[3] = b[3];
|
||||
|
||||
// Put bits in hash in LE byte order on BE machines.
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
b[0] = Utils::swapBytes(b[0]);
|
||||
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]);
|
||||
#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;
|
||||
s16.initXY(b[4],b[5]);
|
||||
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);
|
||||
|
||||
// Put bits in little-endian byte order if this is a BE machine.
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
for(unsigned int i=0;i<98304;i+=8) {
|
||||
b[i] = Utils::swapBytes(b[i]);
|
||||
|
@ -143,7 +154,14 @@ bool _v1_identity_generate_cond(const void *in,const unsigned int len)
|
|||
}
|
||||
#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);
|
||||
|
||||
// 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
|
||||
const uint64_t finalHash = Utils::swapBytes(b[0]) + Utils::swapBytes(b[1]);
|
||||
#else
|
||||
|
@ -168,7 +186,7 @@ bool Identity::generate(const Type t)
|
|||
uint8_t digest[64];
|
||||
char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
|
||||
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);
|
||||
} while (_address.isReserved());
|
||||
delete[] genmem;
|
||||
|
@ -182,7 +200,7 @@ v1_pow_new_keys:
|
|||
C25519::generate(_pub.c25519,_priv.c25519);
|
||||
ECC384GenerateKey(_pub.p384,_priv.p384);
|
||||
for (;;) {
|
||||
if (_v1_identity_generate_cond(&_pub,sizeof(_pub)))
|
||||
if (identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub)))
|
||||
break;
|
||||
if (++_pub.nonce == 0) // endian-ness doesn't matter, just change the nonce each time
|
||||
goto v1_pow_new_keys;
|
||||
|
@ -211,13 +229,13 @@ bool Identity::locallyValidate() const noexcept
|
|||
case C25519: {
|
||||
uint8_t digest[64];
|
||||
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;
|
||||
return ((_address == Address(digest + 59)) && (digest[0] < 17));
|
||||
}
|
||||
|
||||
case P384:
|
||||
return ( (_address == Address(_fp.hash())) && _v1_identity_generate_cond(&_pub,sizeof(_pub)) );
|
||||
return ((_address == Address(_fp.hash())) && identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub)) );
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue