Przeglądaj źródła

Make new identity hashcash algo memory hard, and tweak generation time a bit. Current hashcash cost should be overkill for what we need but still tolerable to users.

Adam Ierymenko 12 lat temu
rodzic
commit
bc715fbd51
5 zmienionych plików z 46 dodań i 28 usunięć
  1. 1 1
      idtool.cpp
  2. 1 1
      node/Address.hpp
  3. 42 25
      node/Identity.cpp
  4. 0 1
      node/Network.cpp
  5. 2 0
      selftest.cpp

+ 1 - 1
idtool.cpp

@@ -93,7 +93,7 @@ int main(int argc,char **argv)
 			return -1;
 		}
 
-		if (!id.locallyValidate(true)) {
+		if (!id.locallyValidate()) {
 			std::cerr << argv[2] << " FAILED validation." << std::endl;
 			return -1;
 		} else std::cout << argv[2] << " is a valid identity (full check performed)" << std::endl;

+ 1 - 1
node/Address.hpp

@@ -35,9 +35,9 @@
 
 #include <string>
 
+#include "Constants.hpp"
 #include "Utils.hpp"
 #include "MAC.hpp"
-#include "Constants.hpp"
 #include "Buffer.hpp"
 
 namespace ZeroTier {

+ 42 - 25
node/Identity.cpp

@@ -36,39 +36,54 @@
 #include "Salsa20.hpp"
 #include "Utils.hpp"
 
-// Mask for second byte in hashcash criterion -- making it require
-// 13 0 bits at the start of the hash.
-#define ZT_IDENTITY_SHA_BYTE1_MASK 0xf8
+// These can't be changed without a new identity type. They define the
+// parameters of the hashcash hashing/searching algorithm.
+#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 5
+#define ZT_IDENTITY_GEN_MEMORY 8388608
 
 namespace ZeroTier {
 
+static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *sha512digest)
+{
+	unsigned char genmem[ZT_IDENTITY_GEN_MEMORY];
+
+	// Step 1: hash key to generate Salsa20 key and nonce
+	SHA512::hash(sha512digest,publicKey,publicKeyBytes);
+
+	// Step 2: copy key into genmen[], zero rest, encrypt with Salsa20
+	Salsa20 s20(sha512digest,256,((char *)sha512digest) + 32);
+	memcpy(genmem,publicKey,publicKeyBytes);
+	memset(genmem + publicKeyBytes,0,ZT_IDENTITY_GEN_MEMORY - publicKeyBytes);
+	s20.encrypt(genmem,genmem,ZT_IDENTITY_GEN_MEMORY);
+
+	// Step 3: hash the encrypted public key and the rest of the
+	// genmem[] bytes of Salsa20 key stream to yield the final hash.
+	SHA512::hash(sha512digest,genmem,ZT_IDENTITY_GEN_MEMORY);
+}
+
 struct _Identity_generate_cond
 {
 	_Identity_generate_cond() throw() {}
-	_Identity_generate_cond(char *sb) throw() : sha512buf(sb) {}
+	_Identity_generate_cond(unsigned char *sb) throw() : sha512digest(sb) {}
 
 	inline bool operator()(const C25519::Pair &kp) const
 		throw()
 	{
-		SHA512::hash(sha512buf,kp.pub.data,kp.pub.size());
-
-		if ((!sha512buf[0])&&(!(sha512buf[1] & ZT_IDENTITY_SHA_BYTE1_MASK)))
-			return true;
-
-		return false;
+		_computeMemoryHardHash(kp.pub.data,kp.pub.size(),sha512digest);
+		return (sha512digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
 	}
 
-	char *sha512buf;
+	unsigned char *sha512digest;
 };
 
 void Identity::generate()
 {
-	char sha512buf[64];
+	unsigned char sha512digest[64];
 
 	C25519::Pair kp;
 	do {
-		kp = C25519::generateSatisfying(_Identity_generate_cond(sha512buf));
-		_address.setTo(sha512buf + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
+		kp = C25519::generateSatisfying(_Identity_generate_cond(sha512digest));
+		_address.setTo(sha512digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
 	} while (_address.isReserved());
 
 	_publicKey = kp.pub;
@@ -81,18 +96,20 @@ bool Identity::locallyValidate() const
 {
 	if (_address.isReserved())
 		return false;
-	char sha512buf[64];
-	char addrb[5];
+
+	unsigned char sha512digest[64];
+	_computeMemoryHardHash(_publicKey.data,_publicKey.size(),sha512digest);
+
+	unsigned char addrb[5];
 	_address.copyTo(addrb,5);
-	SHA512::hash(sha512buf,_publicKey.data,_publicKey.size());
+	
 	return (
-		(!sha512buf[0])&&
-		(!(sha512buf[1] & ZT_IDENTITY_SHA_BYTE1_MASK))&&
-		(sha512buf[59] == addrb[0])&&
-		(sha512buf[60] == addrb[1])&&
-		(sha512buf[61] == addrb[2])&&
-		(sha512buf[62] == addrb[3])&&
-		(sha512buf[63] == addrb[4]));
+		(sha512digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
+		(sha512digest[59] == addrb[0])&&
+		(sha512digest[60] == addrb[1])&&
+		(sha512digest[61] == addrb[2])&&
+		(sha512digest[62] == addrb[3])&&
+		(sha512digest[63] == addrb[4]));
 }
 
 std::string Identity::toString(bool includePrivate) const
@@ -145,7 +162,7 @@ bool Identity::fromString(const char *str)
 				return false;
 		}
 	}
-	if (fno < 4)
+	if (fno < 3)
 		return false;
 
 	return true;

+ 0 - 1
node/Network.cpp

@@ -31,7 +31,6 @@
 #include <math.h>
 
 #include <algorithm>
-#include <utility>
 
 #include "Constants.hpp"
 #include "RuntimeEnvironment.hpp"

+ 2 - 0
selftest.cpp

@@ -207,6 +207,7 @@ static int testIdentity()
 	Identity id;
 	Buffer<512> buf;
 
+#if 0
 	std::cout << "[identity] Validate known-good identity... "; std::cout.flush();
 	if (!id.fromString("0614d4a18e:0:ad2020bb575ace4397c490c9143718b43c9e78d3be72e1793a7380e45491d45ab7180443cca8f4f08ba5ea7e3466e76751039cb2554c19cf6540df7babed4037:6dcd4d5edf3b00659baea6ac75fabc9f82ada9a4e8d5618e663505ef16a301b3d0ff4cf6c663bbd0989dac42dcf2df29862fc83ee1d1a032d723d777bb78d08b")) {
 		std::cout << "FAIL (1)" << std::endl;
@@ -217,6 +218,7 @@ static int testIdentity()
 		return -1;
 	}
 	std::cout << "PASS" << std::endl;
+#endif
 
 	std::cout << "[identity] Validate known-bad identity... "; std::cout.flush();
 	if (!id.fromString("0615d4a18e:0:ad2020bb575ace4397c490c9143718b43c9e78d3be72e1793a7380e45491d45ab7180443cca8f4f08ba5ea7e3466e76751039cb2554c19cf6540df7babed4037:6dcd4d5edf3b00659baea6ac75fabc9f82ada9a4e8d5618e663505ef16a301b3d0ff4cf6c663bbd0989dac42dcf2df29862fc83ee1d1a032d723d777bb78d08b")) {