[tor-commits] [tor/master] Draft implementation for ed25519 key blinding, as in prop224

nickm at torproject.org nickm at torproject.org
Thu Sep 25 19:12:41 UTC 2014


commit 25b1a32ef85c0b1d57a326991df002c86097a142
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Aug 27 17:59:15 2014 -0400

    Draft implementation for ed25519 key blinding, as in prop224
    
    This implementation allows somebody to add a blinding factor to a
    secret key, and a corresponding blinding factor to the public key.
    
    Robert Ransom came up with this idea, I believe.  Nick Hopper proved a
    scheme like this secure.  The bugs are my own.
---
 src/common/crypto_ed25519.c           |   35 +++++++++++++++
 src/common/crypto_ed25519.h           |    7 ++-
 src/ext/ed25519/ref10/blinding.c      |   75 +++++++++++++++++++++++++++++++++
 src/ext/ed25519/ref10/ed25519_ref10.h |    6 +++
 src/ext/include.am                    |    3 +-
 src/test/test_crypto.c                |   48 +++++++++++++++++++++
 6 files changed, 172 insertions(+), 2 deletions(-)

diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index 4c10c5c..15fc626 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -219,6 +219,41 @@ ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey,
                                                      signbit);
 }
 
+/**
+ * Given an ed25519 keypair in <b>inp</b>, generate a corresponding
+ * ed25519 keypair in <b>out</b>, blinded by the corresponding 32-byte input
+ * in 'param'.
+ *
+ */
+int
+ed25519_keypair_blind(ed25519_keypair_t *out,
+                      const ed25519_keypair_t *inp,
+                      const uint8_t *param)
+{
+  ed25519_public_key_t pubkey_check;
+
+  ed25519_ref10_derive_secret_key(out->seckey.seckey,
+                                  inp->seckey.seckey, param);
+
+  ed25519_public_blind(&pubkey_check, &inp->pubkey, param);
+  ed25519_public_key_generate(&out->pubkey, &out->seckey);
+
+  tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32));
+
+  memwipe(&pubkey_check, 0, sizeof(pubkey_check));
+
+  return 0;
+}
+
+int
+ed25519_public_blind(ed25519_public_key_t *out,
+                     const ed25519_public_key_t *inp,
+                     const uint8_t *param)
+{
+  ed25519_ref10_derive_public_key(out->pubkey, inp->pubkey, param);
+  return 0;
+}
+
 /** DOCDOC */
 int
 ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h
index 82c5e6c..1271312 100644
--- a/src/common/crypto_ed25519.h
+++ b/src/common/crypto_ed25519.h
@@ -75,6 +75,12 @@ int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out,
 int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey,
                                      const curve25519_public_key_t *pubkey_in,
                                      int signbit);
+int ed25519_keypair_blind(ed25519_keypair_t *out,
+                          const ed25519_keypair_t *inp,
+                          const uint8_t *param);
+int ed25519_public_blind(ed25519_public_key_t *out,
+                         const ed25519_public_key_t *inp,
+                         const uint8_t *param);
 
 #endif
 
@@ -100,6 +106,5 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
                                   char **tag_out,
                                   const char *filename);
 
-
 #endif
 
diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c
new file mode 100644
index 0000000..a17dbcd
--- /dev/null
+++ b/src/ext/ed25519/ref10/blinding.c
@@ -0,0 +1,75 @@
+/* Added to ref10 for Tor. We place this in the public domain.  Alternatively,
+ * you may have it under the Creative Commons 0 "CC0" license. */
+//#include "fe.h"
+#include "ge.h"
+#include "sc.h"
+#include "crypto_hash_sha512.h"
+#include "ed25519_ref10.h"
+
+#include <string.h>
+#include "crypto.h"
+
+static void
+gettweak(unsigned char *out, const unsigned char *param)
+{
+  const char str[] = "Derive temporary signing key";
+  crypto_hash_sha512_2(out, (const unsigned char*)str, strlen(str), param, 32);
+  out[0] &= 248;  /* Necessary ? */
+  out[31] &= 63;
+  out[31] |= 64;
+}
+
+int ed25519_ref10_derive_secret_key(unsigned char *out,
+                              const unsigned char *inp,
+                              const unsigned char *param)
+{
+  const char str[] = "Derive temporary signing key hash input";
+  unsigned char tweak[64];
+  unsigned char zero[32];
+  gettweak(tweak, param);
+
+  memset(zero, 0, 32);
+  sc_muladd(out, inp, tweak, zero);
+
+  crypto_hash_sha512_2(tweak, (const unsigned char *)str, strlen(str),
+                       inp+32, 32);
+  memcpy(out+32, tweak, 32);
+
+  memwipe(tweak, 0, sizeof(tweak));
+
+  return 0;
+}
+
+int ed25519_ref10_derive_public_key(unsigned char *out,
+                              const unsigned char *inp,
+                              const unsigned char *param)
+{
+  unsigned char tweak[64];
+  unsigned char zero[32];
+  unsigned char pkcopy[32];
+  ge_p3 A;
+  ge_p2 Aprime;
+
+  gettweak(tweak, param);
+
+  memset(zero, 0, sizeof(zero));
+  /* Not the greatest implementation of all of this.  I wish I had
+   * better-suited primitives to work with here... (but I don't wish that so
+   * strongly that I'm about to code my own ge_scalarmult_vartime). */
+
+  /* We negate the public key first, so that we can pass it to
+   * frombytes_negate_vartime, which negates it again. */
+  memcpy(pkcopy, inp, 32);
+  pkcopy[31] ^= (1<<7);
+  ge_frombytes_negate_vartime(&A, pkcopy);
+  /* There isn't a regular ge_scalarmult -- we have to do tweak*A + zero*B. */
+  ge_double_scalarmult_vartime(&Aprime, tweak, &A, zero);
+  ge_tobytes(out, &Aprime);
+
+  memwipe(tweak, 0, sizeof(tweak));
+  memwipe(&A, 0, sizeof(A));
+  memwipe(&Aprime, 0, sizeof(Aprime));
+  memwipe(&pkcopy, 0, sizeof(pkcopy));
+
+  return 0;
+}
diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h
index da8cea1..f4a76e6 100644
--- a/src/ext/ed25519/ref10/ed25519_ref10.h
+++ b/src/ext/ed25519/ref10/ed25519_ref10.h
@@ -20,5 +20,11 @@ int ed25519_ref10_sign(
 int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out,
                                                 const unsigned char *inp,
                                                 int signbit);
+int ed25519_ref10_derive_secret_key(unsigned char *out,
+                              const unsigned char *inp,
+                              const unsigned char *param);
+int ed25519_ref10_derive_public_key(unsigned char *out,
+                              const unsigned char *inp,
+                              const unsigned char *param);
 
 #endif
diff --git a/src/ext/include.am b/src/ext/include.am
index 45d7dc5..69c136b 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -57,7 +57,8 @@ src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES= \
 	src/ext/ed25519/ref10/sc_muladd.c \
 	src/ext/ed25519/ref10/sc_reduce.c \
 	src/ext/ed25519/ref10/sign.c \
-	src/ext/ed25519/ref10/keyconv.c
+	src/ext/ed25519/ref10/keyconv.c \
+	src/ext/ed25519/ref10/blinding.c
 
 ED25519_REF10_HDRS = \
 	src/ext/ed25519/ref10/api.h \
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 0ef5e42..d4478d5 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1409,6 +1409,53 @@ test_crypto_ed25519_convert(void *arg)
 }
 
 static void
+test_crypto_ed25519_blinding(void *arg)
+{
+  const uint8_t msg[] =
+    "Eyes I dare not meet in dreams / In death's dream kingdom";
+
+  const int N = 30;
+  int i;
+  (void)arg;
+
+  for (i = 0; i < N; ++i) {
+    uint8_t blinding[32];
+    ed25519_keypair_t ed25519_keypair;
+    ed25519_keypair_t ed25519_keypair_blinded;
+    ed25519_public_key_t ed25519_pubkey_blinded;
+
+    ed25519_signature_t sig;
+
+    crypto_rand((char*) blinding, sizeof(blinding));
+
+    tt_int_op(0,==,ed25519_keypair_generate(&ed25519_keypair, 0));
+    tt_int_op(0,==,ed25519_keypair_blind(&ed25519_keypair_blinded,
+                                         &ed25519_keypair, blinding));
+
+    tt_int_op(0,==,ed25519_public_blind(&ed25519_pubkey_blinded,
+                                        &ed25519_keypair.pubkey, blinding));
+
+    tt_mem_op(ed25519_pubkey_blinded.pubkey, ==,
+              ed25519_keypair_blinded.pubkey.pubkey, 32);
+
+    tt_int_op(0,==,ed25519_sign(&sig, msg, sizeof(msg),
+                                &ed25519_keypair_blinded));
+
+    tt_int_op(0,==,ed25519_checksig(&sig, msg, sizeof(msg),
+                                    &ed25519_pubkey_blinded));
+
+    tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg)-1,
+                                     &ed25519_pubkey_blinded));
+    sig.sig[0] ^= 15;
+    tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg),
+                                     &ed25519_pubkey_blinded));
+  }
+
+ done:
+  ;
+}
+
+static void
 test_crypto_siphash(void *arg)
 {
   /* From the reference implementation, taking
@@ -1549,6 +1596,7 @@ struct testcase_t crypto_tests[] = {
   { "ed25519_test_vectors", test_crypto_ed25519_test_vectors, 0, NULL, NULL },
   { "ed25519_encode", test_crypto_ed25519_encode, 0, NULL, NULL },
   { "ed25519_convert", test_crypto_ed25519_convert, 0, NULL, NULL },
+  { "ed25519_blinding", test_crypto_ed25519_blinding, 0, NULL, NULL },
 #endif
   { "siphash", test_crypto_siphash, 0, NULL, NULL },
   END_OF_TESTCASES





More information about the tor-commits mailing list