Browse Source

The MIMC thing was neat but unfortunately is amenable to too much GPU acceleration.

Adam Ierymenko 5 years ago
parent
commit
8a379ba0a1
8 changed files with 64 additions and 70 deletions
  1. 0 0
      attic/MIMC52.cpp
  2. 0 0
      attic/MIMC52.hpp
  3. 0 2
      node/CMakeLists.txt
  4. 48 20
      node/Identity.cpp
  5. 2 2
      node/Identity.hpp
  6. 1 1
      node/Salsa20.hpp
  7. 11 42
      node/Tests.cpp
  8. 2 3
      node/Utils.cpp

+ 0 - 0
node/MIMC52.cpp → attic/MIMC52.cpp


+ 0 - 0
node/MIMC52.hpp → attic/MIMC52.hpp


+ 0 - 2
node/CMakeLists.txt

@@ -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

+ 48 - 20
node/Identity.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)) );
 
 			}
 		}

+ 2 - 2
node/Identity.hpp

@@ -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;

+ 1 - 1
node/Salsa20.hpp

@@ -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>

+ 11 - 42
node/Tests.cpp

@@ -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)

+ 2 - 3
node/Utils.cpp

@@ -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;
 	}
 }