diff --git a/Crypto.cpp b/Crypto.cpp
index 0ec0f020..fe6dfa8f 100644
--- a/Crypto.cpp
+++ b/Crypto.cpp
@@ -148,11 +148,88 @@ namespace crypto
 // DH/ElGamal	
 
 	const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
+	const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
 	const int ELGAMAL_FULL_EXPONENT_NUM_BITS = 2048;
 
 	#define elgp GetCryptoConstants ().elgp
 	#define elgg GetCryptoConstants ().elgg
 
+#if !defined(__x86_64__) // use precalculated table
+
+	static BN_MONT_CTX * g_MontCtx = nullptr;
+	static void PrecalculateElggTable (BIGNUM * table[][255], int len) // table is len's array of array of 255 bignums
+	{
+		if (len <= 0) return;
+		BN_CTX * ctx = BN_CTX_new ();
+		g_MontCtx = BN_MONT_CTX_new ();
+		BN_MONT_CTX_set (g_MontCtx, elgp, ctx);		
+		auto montCtx = BN_MONT_CTX_new ();
+		BN_MONT_CTX_copy (montCtx, g_MontCtx);
+		for (int i = 0; i < len; i++)
+		{
+			table[i][0] = BN_new ();
+			if (!i) 	
+				BN_to_montgomery (table[0][0], elgg, montCtx, ctx); 	
+			else
+				BN_mod_mul_montgomery (table[i][0], table[i-1][254], table[i-1][0], montCtx, ctx);
+			for (int j = 1; j < 255; j++)
+			{
+				table[i][j] = BN_new ();
+				BN_mod_mul_montgomery (table[i][j], table[i][j-1], table[i][0], montCtx, ctx);
+			}
+		}
+		BN_MONT_CTX_free (montCtx);
+		BN_CTX_free (ctx);
+	}	 
+
+	static void DestroyElggTable (BIGNUM * table[][255], int len)
+	{
+		for (int i = 0; i < len; i++)
+			for (int j = 0; j < 255; j++)
+			{
+				BN_free (table[i][j]);
+				table[i][j] = nullptr;
+			}
+		BN_MONT_CTX_free (g_MontCtx);
+	}
+	
+	static BIGNUM * ElggPow (const uint8_t * exp, int len, BIGNUM * table[][255], BN_CTX * ctx)
+	// exp is in Big Endian	
+	{
+		if (len <= 0) return nullptr;
+		auto montCtx = BN_MONT_CTX_new ();
+		BN_MONT_CTX_copy (montCtx, g_MontCtx);
+		BIGNUM * res = nullptr;
+		for (int i = 0; i < len; i++)
+		{
+			if (res)
+			{
+				if (exp[i])
+					BN_mod_mul_montgomery (res, res, table[len-1-i][exp[i]-1], montCtx, ctx);
+			}	
+			else if (exp[i]) 
+				res = BN_dup (table[len-i-1][exp[i]-1]);
+		}	
+		if (res)
+			BN_from_montgomery (res, res, montCtx, ctx);
+		BN_MONT_CTX_free (montCtx);
+		return res;
+	}	
+
+	static BIGNUM * ElggPow (const BIGNUM * exp, BIGNUM * table[][255], BN_CTX * ctx)
+	{
+		auto len = BN_num_bytes (exp);
+		uint8_t * buf = new uint8_t[len];
+		BN_bn2bin (exp, buf);
+		auto ret = ElggPow (buf, len, table, ctx);
+		delete[] buf;
+		return ret;
+	}	
+
+	BIGNUM * g_ElggTable[ELGAMAL_SHORT_EXPONENT_NUM_BYTES][255];
+	
+#endif
+	
 // DH
 	
 	DHKeys::DHKeys (): m_IsUpdated (true)
@@ -173,11 +250,15 @@ namespace crypto
 	{
 		if (m_DH->priv_key)  { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; };
 		if (m_DH->pub_key)  { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; };
-#if !defined(__x86_64__) // use short exponent for non x64
+#if !defined(__x86_64__) // use short exponent for non x64 
 		m_DH->priv_key = BN_new ();
-		BN_rand (m_DH->priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);	
-#endif
+		BN_rand (m_DH->priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
+		auto ctx = BN_CTX_new ();
+		m_DH->pub_key = ElggPow (m_DH->priv_key, g_ElggTable, ctx);
+		BN_CTX_free (ctx);
+#else
 		DH_generate_key (m_DH);
+#endif		
 		if (priv) bn2buf (m_DH->priv_key, priv, 256);
 		if (pub) bn2buf (m_DH->pub_key, pub, 256);
 		m_IsUpdated = true;
@@ -210,12 +291,14 @@ namespace crypto
 		BIGNUM * k = BN_new ();
 #if defined(__x86_64__)
 		BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
-#else
-		BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
-#endif
-		// caulculate a
+		// calculate a
 		a = BN_new ();
 		BN_mod_exp (a, elgg, k, elgp, ctx);
+#else
+		BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
+		// calculate a
+		a = ElggPow (k, g_ElggTable, ctx);
+#endif
 		BIGNUM * y = BN_new ();
 		BN_bin2bn (key, 256, y);
 		// calculate b1
@@ -716,10 +799,16 @@ namespace crypto
 		for (int i = 0; i < numLocks; i++)
 		     m_OpenSSLMutexes.emplace_back (new std::mutex);
 		CRYPTO_set_locking_callback (OpensslLockingCallback);*/
+#if !defined(__x86_64__)		
+		PrecalculateElggTable (g_ElggTable, ELGAMAL_SHORT_EXPONENT_NUM_BYTES);
+#endif		
 	}
 	
 	void TerminateCrypto ()
 	{
+#if !defined(__x86_64__)		
+		DestroyElggTable (g_ElggTable, ELGAMAL_SHORT_EXPONENT_NUM_BYTES);
+#endif		
 /*		CRYPTO_set_locking_callback (nullptr);
 		m_OpenSSLMutexes.clear ();*/
 	}	
diff --git a/README.md b/README.md
index 4f167754..b985abf4 100644
--- a/README.md
+++ b/README.md
@@ -15,14 +15,11 @@ Donations
 BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY  
 LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59  
 ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z  
+DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y 
 
-Downloads
-------------
-
-Official binary releases could be found at:  
-http://i2pd.website/releases/  
-older releases  
-http://download.i2p.io/purplei2p/i2pd/releases/  
+Documentation:
+--------------
+http://i2pd.readthedocs.org
 
 Supported OS
 ------------
diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp
index a3907ce5..842b624f 100644
--- a/TunnelEndpoint.cpp
+++ b/TunnelEndpoint.cpp
@@ -119,7 +119,7 @@ namespace tunnel
 							if (ret.second)
 								HandleOutOfSequenceFragment (msgID, ret.first->second);
 							else
-								LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, "already exists");
+								LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, " already exists");
 						}
 						else
 						{
diff --git a/Win32/Resource.rc b/Win32/Resource.rc
index bdc532e9..c885c044 100644
--- a/Win32/Resource.rc
+++ b/Win32/Resource.rc
@@ -52,8 +52,8 @@ END
 
 // Icon with lowest ID value placed first to ensure application icon
 // remains consistent on all systems.
-//MAINICON                ICON                    "ictoopie.ico"
-MAINICON                ICON                    "anke.ico"
+MAINICON                ICON                    "ictoopie.ico"
+//MAINICON                ICON                    "anke.ico"
 
 MASCOT					BITMAP					"Anke_700px.bmp"