Parcourir la source

Some API improvements to C25519 in preparation for that thing I woke up thinking about at 4am.

Adam Ierymenko il y a 12 ans
Parent
commit
588a47be89
2 fichiers modifiés avec 80 ajouts et 35 suppressions
  1. 30 32
      node/C25519.cpp
  2. 50 3
      node/C25519.hpp

+ 30 - 32
node/C25519.cpp

@@ -31,7 +31,6 @@
 
 #include "Constants.hpp"
 #include "C25519.hpp"
-#include "Utils.hpp"
 #include "SHA512.hpp"
 #include "Buffer.hpp"
 
@@ -2288,37 +2287,6 @@ static int crypto_sign_open(
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-C25519::Pair C25519::generate()
-  throw()
-{
-  unsigned char extsk[64];
-  sc25519 scsk;
-  ge25519 gepk;
-	Pair kp;
-
-	Utils::getSecureRandom(kp.priv.data,kp.priv.size());
-
-	// First 32 bytes of pub and priv are the keys for C25519 key
-	// agreement. This generates the public portion from the private.
-	crypto_scalarmult_base(kp.pub.data,kp.priv.data);
-
-  // Second 32 bytes of pub and priv are the keys for ed25519
-  // signing and verification.
-  SHA512::hash(extsk,kp.priv.data + 32,32);
-  extsk[0] &= 248;
-  extsk[31] &= 127;
-  extsk[31] |= 64;
-  sc25519_from32bytes(&scsk,extsk);
-  ge25519_scalarmult_base(&gepk,&scsk);
-  ge25519_pack(kp.pub.data + 32,&gepk);
-  // In NaCl, the public key is crammed into the next 32 bytes
-  // of the private key for signing since both keys are required
-  // to sign. In this case we just get it from public, so we
-  // leave that out of private.
-
-	return kp;
-}
-
 void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
   throw()
 {
@@ -2417,4 +2385,34 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len
   return Utils::secureEq(sig,t2,32);
 }
 
+void C25519::_calcPubDH(C25519::Pair &kp)
+  throw()
+{
+  // First 32 bytes of pub and priv are the keys for ECDH key
+  // agreement. This generates the public portion from the private.
+  crypto_scalarmult_base(kp.pub.data,kp.priv.data);
+}
+
+void C25519::_calcPubED(C25519::Pair &kp)
+  throw()
+{
+  unsigned char extsk[64];
+  sc25519 scsk;
+  ge25519 gepk;
+
+  // Second 32 bytes of pub and priv are the keys for ed25519
+  // signing and verification.
+  SHA512::hash(extsk,kp.priv.data + 32,32);
+  extsk[0] &= 248;
+  extsk[31] &= 127;
+  extsk[31] |= 64;
+  sc25519_from32bytes(&scsk,extsk);
+  ge25519_scalarmult_base(&gepk,&scsk);
+  ge25519_pack(kp.pub.data + 32,&gepk);
+  // In NaCl, the public key is crammed into the next 32 bytes
+  // of the private key for signing since both keys are required
+  // to sign. In this version we just get it from kp.pub, so we
+  // leave that out of private.
+}
+
 } // namespace ZeroTier

+ 50 - 3
node/C25519.hpp

@@ -29,6 +29,7 @@
 #define _ZT_C25519_HPP
 
 #include "Array.hpp"
+#include "Utils.hpp"
 
 namespace ZeroTier {
 
@@ -37,7 +38,7 @@ namespace ZeroTier {
 #define ZT_C25519_SIGNATURE_LEN 96
 
 /**
- * C25519 elliptic curve key agreement and signing
+ * A combined Curve25519 ECDH and Ed25519 signature engine
  */
 class C25519
 {
@@ -68,8 +69,43 @@ public:
 	/**
 	 * Generate a C25519 elliptic curve key pair
 	 */
-	static Pair generate()
-		throw();
+	static inline Pair generate()
+		throw()
+	{
+		Pair kp;
+		Utils::getSecureRandom(kp.priv.data,kp.priv.size());
+		_calcPubDH(kp);
+		_calcPubED(kp);
+		return kp;
+	}
+
+	/**
+	 * Generate a key pair satisfying a condition
+	 *
+	 * This begins with a random keypair from a random secret key and then
+	 * iteratively increments the random secret until cond(kp) returns true.
+	 * This is used to compute key pairs in which the public key, its hash
+	 * or some other aspect of it satisfies some condition, such as for a
+	 * hashcash criteria.
+	 *
+	 * @param cond Condition function or function object
+	 * @return Key pair where cond(kp) returns true
+	 * @tparam F Type of 'cond'
+	 */
+	template<typename F>
+	static inline Pair generateSatisfying(F cond)
+		throw()
+	{
+		Pair kp;
+		void *const priv = (void *)kp.priv.data;
+		Utils::getSecureRandom(priv,kp.priv.size());
+		_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
+		do {
+			++*((uint64_t *)priv);
+			_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
+		} while (!cond(kp));
+		return kp;
+	}
 
 	/**
 	 * Perform C25519 ECC key agreement
@@ -167,6 +203,17 @@ public:
 	{
 		return verify(their,msg,len,signature.data);
 	}
+
+private:
+	// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
+	// this is the ECDH key
+	static void _calcPubDH(Pair &kp)
+		throw();
+
+	// derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
+	// this is the Ed25519 sign/verify key
+	static void _calcPubED(Pair &kp)
+		throw();
 };
 
 } // namespace ZeroTier