mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
The MIMC thing was neat but unfortunately is amenable to too much GPU acceleration.
This commit is contained in:
parent
4b20638568
commit
8a379ba0a1
8 changed files with 64 additions and 70 deletions
|
@ -24,7 +24,6 @@ set(core_headers
|
|||
LZ4.hpp
|
||||
MAC.hpp
|
||||
Membership.hpp
|
||||
MIMC52.hpp
|
||||
MulticastGroup.hpp
|
||||
Mutex.hpp
|
||||
Network.hpp
|
||||
|
@ -67,7 +66,6 @@ set(core_src
|
|||
Locator.cpp
|
||||
LZ4.cpp
|
||||
Membership.cpp
|
||||
MIMC52.cpp
|
||||
Network.cpp
|
||||
NetworkConfig.cpp
|
||||
Node.cpp
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "SHA512.hpp"
|
||||
#include "Salsa20.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "MIMC52.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
@ -31,7 +30,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
|
||||
static void _computeMemoryHardHash(const void *const publicKey,unsigned int publicKeyBytes,void *const digest,void *const genmem) noexcept
|
||||
void _computeMemoryHardHash(const void *const publicKey,unsigned int publicKeyBytes,void *const digest,void *const genmem) noexcept
|
||||
{
|
||||
// Digest publicKey[] to obtain initial digest
|
||||
SHA512(digest,publicKey,publicKeyBytes);
|
||||
|
@ -67,7 +66,6 @@ static void _computeMemoryHardHash(const void *const publicKey,unsigned int publ
|
|||
}
|
||||
struct _v0_identity_generate_cond
|
||||
{
|
||||
ZT_INLINE _v0_identity_generate_cond() noexcept {}
|
||||
ZT_INLINE _v0_identity_generate_cond(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
|
||||
{
|
||||
|
@ -78,6 +76,44 @@ struct _v0_identity_generate_cond
|
|||
char *genmem;
|
||||
};
|
||||
|
||||
// This is a simpler memory-intensive hash function for V1 identity generation.
|
||||
bool _v1_identity_generate_cond(const void *in,const unsigned int len)
|
||||
{
|
||||
uint64_t b[98304]; // 768 KiB
|
||||
|
||||
SHA512(b,in,len);
|
||||
for(unsigned long i=8;i<98304;i+=8)
|
||||
SHA512(b + i,b + (i - 8),64);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
for(unsigned int i=0;i<131072;i+=8) {
|
||||
b[i] = Utils::swapBytes(b[i]);
|
||||
b[i + 1] = Utils::swapBytes(b[i + 1]);
|
||||
b[i + 2] = Utils::swapBytes(b[i + 2]);
|
||||
b[i + 3] = Utils::swapBytes(b[i + 3]);
|
||||
b[i + 4] = Utils::swapBytes(b[i + 4]);
|
||||
b[i + 5] = Utils::swapBytes(b[i + 5]);
|
||||
b[i + 6] = Utils::swapBytes(b[i + 6]);
|
||||
b[i + 7] = Utils::swapBytes(b[i + 7]);
|
||||
}
|
||||
#endif
|
||||
std::sort(b,b + 98304);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
for(unsigned int i=0;i<131072;i+=8) {
|
||||
b[i] = Utils::swapBytes(b[i]);
|
||||
b[i + 1] = Utils::swapBytes(b[i + 1]);
|
||||
b[i + 2] = Utils::swapBytes(b[i + 2]);
|
||||
b[i + 3] = Utils::swapBytes(b[i + 3]);
|
||||
b[i + 4] = Utils::swapBytes(b[i + 4]);
|
||||
b[i + 5] = Utils::swapBytes(b[i + 5]);
|
||||
b[i + 6] = Utils::swapBytes(b[i + 6]);
|
||||
b[i + 7] = Utils::swapBytes(b[i + 7]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SHA384(b,b,sizeof(b));
|
||||
return reinterpret_cast<uint8_t *>(b)[0] == 0;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
const Identity Identity::NIL;
|
||||
|
@ -103,15 +139,17 @@ bool Identity::generate(const Type t)
|
|||
|
||||
case P384: {
|
||||
for(;;) {
|
||||
// Generate C25519, Ed25519, and NIST P-384 key pairs.
|
||||
_pub.nonce = 0;
|
||||
v1_pow_new_keys:
|
||||
C25519::generate(_pub.c25519,_priv.c25519);
|
||||
ECC384GenerateKey(_pub.p384,_priv.p384);
|
||||
for (;;) {
|
||||
if (_v1_identity_generate_cond(&_pub,sizeof(_pub)))
|
||||
break;
|
||||
if (++_pub.nonce == 0) // endian-ness doesn't matter, just change the nonce each time
|
||||
goto v1_pow_new_keys;
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Compute SHA384 fingerprint hash of keys and MIMC output and generate address directly from it.
|
||||
_computeHash();
|
||||
_address.setTo(_fp.hash());
|
||||
if (!_address.isReserved())
|
||||
|
@ -141,17 +179,7 @@ bool Identity::locallyValidate() const noexcept
|
|||
}
|
||||
|
||||
case P384:
|
||||
if (_address == Address(_fp.hash())) {
|
||||
// The most significant 8 bits of the MIMC proof included with v1 identities can be used to store a multiplier
|
||||
// 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
|
||||
// that is at least ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE.
|
||||
unsigned long rounds = (((unsigned long)_pub.t1mimc52[0] & 15U) + 1U); // max: 16 * ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE
|
||||
rounds *= ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE;
|
||||
return mimc52Verify(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),rounds,Utils::loadBigEndian<uint64_t>(_pub.t1mimc52));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return ( (_address == Address(_fp.hash())) && _v1_identity_generate_cond(&_pub,sizeof(_pub)) );
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <cstring>
|
||||
|
||||
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
|
||||
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + 8)
|
||||
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (1 + ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)
|
||||
#define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_PRIVATE_KEY_LEN + 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)
|
||||
|
||||
|
@ -224,9 +224,9 @@ private:
|
|||
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
|
||||
}) _priv;
|
||||
ZT_PACKED_STRUCT(struct { // do not re-order these fields
|
||||
uint8_t nonce; // nonce for PoW generate/verify
|
||||
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN]; // Curve25519 and Ed25519 public keys
|
||||
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
|
||||
uint8_t t1mimc52[8]; // Type 1 MIMC52 proof and work amount in big-endian byte order
|
||||
}) _pub;
|
||||
Type _type; // _type determines which fields in _priv and _pub are used
|
||||
bool _hasPrivate;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "Utils.hpp"
|
||||
#include "TriviallyCopyable.hpp"
|
||||
|
||||
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||
#ifdef ZT_ARCH_X64
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#include <immintrin.h>
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "FCV.hpp"
|
||||
#include "SHA512.hpp"
|
||||
#include "Defragmenter.hpp"
|
||||
#include "MIMC52.hpp"
|
||||
#include "Fingerprint.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -698,9 +697,10 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[general] Example V1 identity: ");
|
||||
id.generate(Identity::P384);
|
||||
id.toString(true,tmp);
|
||||
ZT_T_PRINTF("[general] Example V1 identity: %s\n",tmp);
|
||||
ZT_T_PRINTF("%s" ZT_EOL_S,tmp);
|
||||
id.fingerprint().toString(tmp);
|
||||
ZT_T_PRINTF("[general] Fingerprint: %s" ZT_EOL_S,tmp);
|
||||
}
|
||||
|
@ -782,24 +782,6 @@ extern "C" const char *ZTT_crypto()
|
|||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[crypto] Testing MIMC52 VDF... ");
|
||||
const uint64_t proof = mimc52Delay("",1,1000);
|
||||
if ((!mimc52Verify("",1,1000,proof))||(proof != 0x000cc1abe2dde7a3)) {
|
||||
ZT_T_PRINTF("FAILED (%.16llx)" ZT_EOL_S,proof);
|
||||
return "MIMC52 failed simple delay/verify test";
|
||||
}
|
||||
for(int i=0;i<1024;++i) {
|
||||
uint64_t in = Utils::random();
|
||||
unsigned long r = 1 + (unsigned long)(Utils::random() % 1024);
|
||||
if (!mimc52Verify(&in,sizeof(in),r,mimc52Delay(&in,sizeof(in),r))) {
|
||||
ZT_T_PRINTF("FAILED (random input test)");
|
||||
return "MIMC52 failed random input test";
|
||||
}
|
||||
}
|
||||
ZT_T_PRINTF("OK (%.16llx)" ZT_EOL_S,proof);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t agree0[32],agree1[32],kh[64],sig[96];
|
||||
ZT_T_PRINTF("[crypto] Testing C25519/Ed25519... ");
|
||||
|
@ -1030,21 +1012,6 @@ extern "C" const char *ZTT_benchmarkCrypto()
|
|||
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 MIMC52 VDF delay... ");
|
||||
int64_t start = now();
|
||||
const uint64_t proof = mimc52Delay("testing",7,250000);
|
||||
int64_t end = now();
|
||||
int64_t dtime = end - start;
|
||||
ZT_T_PRINTF("%.4f μs/round" ZT_EOL_S,((double)dtime * 1000.0) / 250000.0);
|
||||
ZT_T_PRINTF("[crypto] Benchmarking MIMC52 VDF verify... ");
|
||||
start = now();
|
||||
foo = (uint8_t)mimc52Verify("testing",7,1000000,proof); // doesn't matter if return is true or false here
|
||||
end = now();
|
||||
int64_t vtime = end - start;
|
||||
ZT_T_PRINTF("%.8f μs/round, %.4fX faster than delay" ZT_EOL_S,((double)vtime * 1000.0) / 1000000.0,(double)(dtime / 250000.0) / (double)(vtime / 1000000.0));
|
||||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[crypto] Benchmarking AES-CTR... ");
|
||||
AES aes(AES_CTR_TEST_VECTOR_0_KEY);
|
||||
|
@ -1169,29 +1136,31 @@ extern "C" const char *ZTT_benchmarkCrypto()
|
|||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[crypto] Benchmarking V0 Identity generation... ");
|
||||
ZT_T_PRINTF("[crypto] Benchmarking V0 Identity generation...");
|
||||
Identity id;
|
||||
int64_t start = now();
|
||||
for(long i=0;i<5;++i) {
|
||||
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, can vary quite a bit)" ZT_EOL_S,(double)(end - start) / 5.0);
|
||||
ZT_T_PRINTF("[crypto] Benchmarking V0 Identity full validation... ");
|
||||
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... ");
|
||||
ZT_T_PRINTF("[crypto] Benchmarking V1 Identity generation...");
|
||||
start = now();
|
||||
for(long i=0;i<5;++i) {
|
||||
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 (relatively constant time)" ZT_EOL_S,(double)(end - start) / 5.0);
|
||||
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)
|
||||
|
|
|
@ -453,10 +453,9 @@ bool scopy(char *const dest,const unsigned int len,const char *const src) noexce
|
|||
dest[len - 1] = 0;
|
||||
return false;
|
||||
}
|
||||
const char c = src[i];
|
||||
dest[i] = c;
|
||||
if (c == 0)
|
||||
if ((dest[i] = src[i]) == 0)
|
||||
return true;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue