towards less variance
authorSchanzenbach, Martin <mschanzenbach@posteo.de>
Sun, 19 Apr 2020 18:05:26 +0000 (20:05 +0200)
committerSchanzenbach, Martin <mschanzenbach@posteo.de>
Sun, 19 Apr 2020 18:05:26 +0000 (20:05 +0200)
src/include/gnunet_revocation_service.h
src/revocation/gnunet-revocation.c
src/revocation/gnunet-service-revocation.c
src/revocation/plugin_block_revocation.c
src/revocation/revocation.h
src/revocation/revocation_api.c

index 1e1abb7874fa0b7e25015a477378701dc5a56a13..775da01ac7a866e803af453fb37a1657ed2b3ca0 100644 (file)
@@ -50,6 +50,47 @@ extern "C"
  */
 #define GNUNET_REVOCATION_VERSION 0x00000000
 
+/**
+ * The proof-of-work narrowing factor.
+ * The number of PoWs that are calculates as part of revocation.
+ */
+#define POW_COUNT 32
+
+struct GNUNET_REVOCATION_Pow
+{
+  /**
+   * The timestamp of the revocation
+   */
+  struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+  /**
+   * The TTL of this revocation (purely informational)
+   */
+  uint64_t ttl;
+
+  /**
+   * The PoWs
+   */
+  uint64_t pow[POW_COUNT];
+
+  /**
+   * The signature
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+  /**
+   * The signature purpose
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * The revoked public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey key;
+};
+
+struct GNUNET_REVOCATION_PowCalculationHandle;
+
 /**
  * Handle for the key revocation query.
  */
@@ -116,10 +157,7 @@ struct GNUNET_REVOCATION_Handle;
  */
 struct GNUNET_REVOCATION_Handle *
 GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                          const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
-                          const struct GNUNET_CRYPTO_EcdsaSignature *sig,
-                          const struct GNUNET_TIME_Absolute *ts,
-                          uint64_t pow,
+                          const struct GNUNET_REVOCATION_Pow *pow,
                           GNUNET_REVOCATION_Callback func, void *func_cls);
 
 
@@ -143,12 +181,42 @@ GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h);
  * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
  */
 int
-GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
-                             const struct GNUNET_TIME_Absolute *ts,
-                             uint64_t pow,
+GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_Pow *pow,
                              unsigned int matching_bits);
 
 
+struct GNUNET_REVOCATION_PowCalculationHandle*
+GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
+                            int epochs,
+                            unsigned int difficulty);
+
+
+/**
+ * Calculate a key revocation valid for broadcasting for a number
+ * of epochs.
+ *
+ * @param pc handle to the PoW, initially called with NULL.
+ * @param epochs number of epochs for which the revocation must be valid.
+ * @param pow current pow value to try
+ * @param difficulty current base difficulty to achieve
+ * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
+ */
+int
+GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc);
+
+
+const struct GNUNET_REVOCATION_Pow*
+GNUNET_REVOCATION_pow_get (const struct
+                           GNUNET_REVOCATION_PowCalculationHandle *pc);
+
+
+void
+GNUNET_REVOCATION_pow_cleanup (struct
+                               GNUNET_REVOCATION_PowCalculationHandle *pc);
+
+
+
+
 /**
  * Create a revocation signature.
  *
@@ -156,9 +224,10 @@ GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
  * @param sig where to write the revocation signature
  */
 void
-GNUNET_REVOCATION_sign_revocation (const struct
-                                   GNUNET_CRYPTO_EcdsaPrivateKey *key,
-                                   struct GNUNET_CRYPTO_EcdsaSignature *sig);
+GNUNET_REVOCATION_sign_revocation (struct
+                                   GNUNET_REVOCATION_Pow *pow,
+                                   const struct
+                                   GNUNET_CRYPTO_EcdsaPrivateKey *key);
 
 
 #if 0                           /* keep Emacsens' auto-indent happy */
index 42ec71d169448c57fd27a9741d1c58746a064ba5..2d83da8b6ad6170ea75e71eb2634aeea9d71ca16 100644 (file)
@@ -218,16 +218,12 @@ struct RevocationData
  * Perform the revocation.
  */
 static void
-perform_revocation (const struct RevocationData *rd)
+perform_revocation (const struct GNUNET_REVOCATION_Pow *pow)
 {
   struct GNUNET_TIME_Absolute ts;
 
-  ts = GNUNET_TIME_absolute_ntoh (rd->ts);
   h = GNUNET_REVOCATION_revoke (cfg,
-                                &rd->key,
-                                &rd->sig,
-                                &ts,
-                                rd->pow,
+                                pow,
                                 &print_revocation_result,
                                 NULL);
 }
@@ -240,13 +236,13 @@ perform_revocation (const struct RevocationData *rd)
  * @param rd data to sync
  */
 static void
-sync_rd (const struct RevocationData *rd)
+sync_pow (const struct GNUNET_REVOCATION_Pow *pow)
 {
   if ((NULL != filename) &&
-      (sizeof(struct RevocationData) ==
+      (sizeof(struct GNUNET_REVOCATION_Pow) ==
        GNUNET_DISK_fn_write (filename,
-                             &rd,
-                             sizeof(rd),
+                             &pow,
+                             sizeof(pow),
                              GNUNET_DISK_PERM_USER_READ
                              | GNUNET_DISK_PERM_USER_WRITE)))
     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
@@ -261,15 +257,14 @@ sync_rd (const struct RevocationData *rd)
 static void
 calculate_pow_shutdown (void *cls)
 {
-  struct RevocationData *rd = cls;
+  struct GNUNET_REVOCATION_PowCalculationHandle *ph = cls;
 
   if (NULL != pow_task)
   {
     GNUNET_SCHEDULER_cancel (pow_task);
     pow_task = NULL;
   }
-  sync_rd (rd);
-  GNUNET_free (rd);
+  GNUNET_REVOCATION_pow_cleanup (ph);
 }
 
 
@@ -281,40 +276,27 @@ calculate_pow_shutdown (void *cls)
 static void
 calculate_pow (void *cls)
 {
-  struct RevocationData *rd = cls;
-  struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_ntoh (rd->ts);
+  struct GNUNET_REVOCATION_PowCalculationHandle *ph = cls;
 
   /* store temporary results */
   pow_task = NULL;
-  if (0 == (rd->pow % 128))
-    sync_rd (rd);
-  /* display progress estimate */
-  if ((0 == ((1 << matching_bits) / 100 / 50)) ||
-      (0 == (rd->pow % ((1 << matching_bits) / 100 / 50))))
-    fprintf (stderr, "%s", ".");
-  if ((0 != rd->pow) && ((0 == ((1 << matching_bits) / 100)) ||
-                         (0 == (rd->pow % ((1 << matching_bits) / 100)))))
-    fprintf (stderr,
-             " - @ %3u%% (estimate)\n",
-             (unsigned int) (rd->pow * 100) / (1 << matching_bits));
+  //if (0 == (rd->pow % 128))
+  //  sync_rd (rd);
   /* actually do POW calculation */
-  rd->pow++;
-  if (GNUNET_OK == GNUNET_REVOCATION_check_pow (&rd->key,
-                                                &ts,
-                                                rd->pow,
-                                                (unsigned int) matching_bits))
+  if (GNUNET_OK == GNUNET_REVOCATION_pow_round (ph))
   {
+    const struct GNUNET_REVOCATION_Pow *pow = GNUNET_REVOCATION_pow_get (ph);
     if ((NULL != filename) &&
-        (sizeof(struct RevocationData) !=
+        (sizeof(struct GNUNET_REVOCATION_Pow) !=
          GNUNET_DISK_fn_write (filename,
-                               rd,
-                               sizeof(struct RevocationData),
+                               pow,
+                               sizeof(struct GNUNET_REVOCATION_Pow),
                                GNUNET_DISK_PERM_USER_READ
                                | GNUNET_DISK_PERM_USER_WRITE)))
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
     if (perform)
     {
-      perform_revocation (rd);
+      perform_revocation (pow);
     }
     else
     {
@@ -327,7 +309,7 @@ calculate_pow (void *cls)
     }
     return;
   }
-  pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, rd);
+  pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
 }
 
 
@@ -340,9 +322,8 @@ calculate_pow (void *cls)
 static void
 ego_callback (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
 {
-  struct RevocationData *rd;
+  struct GNUNET_REVOCATION_Pow *pow;
   struct GNUNET_CRYPTO_EcdsaPublicKey key;
-  struct GNUNET_TIME_Absolute ts;
 
   el = NULL;
   if (NULL == ego)
@@ -352,49 +333,49 @@ ego_callback (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
     return;
   }
   GNUNET_IDENTITY_ego_get_public_key (ego, &key);
-  rd = GNUNET_new (struct RevocationData);
+  pow = GNUNET_new (struct GNUNET_REVOCATION_Pow);
   if ((NULL != filename) && (GNUNET_YES == GNUNET_DISK_file_test (filename)) &&
-      (sizeof(struct RevocationData) ==
-       GNUNET_DISK_fn_read (filename, rd, sizeof(struct RevocationData))))
+      (sizeof(struct GNUNET_REVOCATION_Pow) ==
+       GNUNET_DISK_fn_read (filename, pow, sizeof(struct
+                                                  GNUNET_REVOCATION_Pow))))
   {
-    if (0 != GNUNET_memcmp (&rd->key, &key))
+    if (0 != GNUNET_memcmp (&pow->key, &key))
     {
       fprintf (stderr,
                _ ("Error: revocation certificate in `%s' is not for `%s'\n"),
                filename,
                revoke_ego);
-      GNUNET_free (rd);
+      GNUNET_free (pow);
       return;
     }
-  }
-  else
-  {
-    GNUNET_REVOCATION_sign_revocation (GNUNET_IDENTITY_ego_get_private_key (
-                                         ego),
-                                       &rd->sig);
-    rd->key = key;
-    rd->ts = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
-  }
-  ts = GNUNET_TIME_absolute_ntoh (rd->ts);
-  if (GNUNET_YES ==
-      GNUNET_REVOCATION_check_pow (&key,
-                                   &ts,
-                                   rd->pow,
-                                   (unsigned int) matching_bits))
-  {
-    fprintf (stderr, "%s", _ ("Revocation certificate ready\n"));
-    if (perform)
-      perform_revocation (rd);
-    else
-      GNUNET_SCHEDULER_shutdown ();
-    GNUNET_free (rd);
+    if (GNUNET_YES ==
+        GNUNET_REVOCATION_check_pow (pow,
+                                     (unsigned int) matching_bits))
+    {
+      fprintf (stderr, "%s", _ ("Revocation certificate ready\n"));
+      if (perform)
+        perform_revocation (pow);
+      else
+        GNUNET_SCHEDULER_shutdown ();
+      GNUNET_free (pow);
+      return;
+    }
+    fprintf (stderr,
+             _ ("Error: revocation certificate in `%s' invalid\n"),
+             filename);
+    GNUNET_free (pow);
     return;
   }
   fprintf (stderr,
            "%s",
            _ ("Revocation certificate not ready, calculating proof of work\n"));
-  pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, rd);
-  GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, rd);
+  GNUNET_free (pow);
+  struct GNUNET_REVOCATION_PowCalculationHandle *ph;
+  ph = GNUNET_REVOCATION_pow_init (&key,
+                                   1, /* Epochs */
+                                   matching_bits);
+  pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
+  GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
 }
 
 
@@ -413,8 +394,7 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
-  struct RevocationData rd;
-  struct GNUNET_TIME_Absolute ts;
+  struct GNUNET_REVOCATION_Pow pow;
 
   cfg = c;
   if (NULL != test_ego)
@@ -463,7 +443,7 @@ run (void *cls,
   }
   if ((NULL != filename) && (perform))
   {
-    if (sizeof(rd) != GNUNET_DISK_fn_read (filename, &rd, sizeof(rd)))
+    if (sizeof(pow) != GNUNET_DISK_fn_read (filename, &pow, sizeof(pow)))
     {
       fprintf (stderr,
                _ ("Failed to read revocation certificate from `%s'\n"),
@@ -471,21 +451,20 @@ run (void *cls,
       return;
     }
     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
-    ts = GNUNET_TIME_absolute_ntoh (rd.ts);
     if (GNUNET_YES !=
-        GNUNET_REVOCATION_check_pow (&rd.key,
-                                     &ts,
-                                     rd.pow,
+        GNUNET_REVOCATION_check_pow (&pow,
                                      (unsigned int) matching_bits))
     {
-      struct RevocationData *cp = GNUNET_new (struct RevocationData);
+      struct GNUNET_REVOCATION_PowCalculationHandle *ph;
+      ph = GNUNET_REVOCATION_pow_init (&pk,
+                                       1, /* Epochs */
+                                       matching_bits);
 
-      *cp = rd;
-      pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cp);
-      GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, cp);
+      pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
+      GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
       return;
     }
-    perform_revocation (&rd);
+    perform_revocation (&pow);
     return;
   }
   fprintf (stderr, "%s", _ ("No action specified. Nothing to do.\n"));
index ff75faa2c904ece3f03608d02a3cb8875f696da5..420cb392f05e9c191b09dd9d321ee155494bf420 100644 (file)
@@ -167,12 +167,8 @@ new_peer_entry (const struct GNUNET_PeerIdentity *peer)
 static int
 verify_revoke_message (const struct RevokeMessage *rm)
 {
-  struct GNUNET_TIME_Absolute ts;
-  ts = GNUNET_TIME_absolute_ntoh (rm->ts);
   if (GNUNET_YES !=
-      GNUNET_REVOCATION_check_pow (&rm->public_key,
-                                   &ts,
-                                   rm->proof_of_work,
+      GNUNET_REVOCATION_check_pow (&rm->proof_of_work,
                                    (unsigned int) revocation_work_required))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -182,9 +178,9 @@ verify_revoke_message (const struct RevokeMessage *rm)
   }
   if (GNUNET_OK !=
       GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
-                                   &rm->purpose,
-                                   &rm->signature,
-                                   &rm->public_key))
+                                   &rm->proof_of_work.purpose,
+                                   &rm->proof_of_work.signature,
+                                   &rm->proof_of_work.key))
   {
     GNUNET_break_op (0);
     return GNUNET_NO;
@@ -311,7 +307,7 @@ publicize_rm (const struct RevokeMessage *rm)
   struct GNUNET_HashCode hc;
   struct GNUNET_SET_Element e;
 
-  GNUNET_CRYPTO_hash (&rm->public_key,
+  GNUNET_CRYPTO_hash (&rm->proof_of_work.key,
                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
                       &hc);
   if (GNUNET_YES ==
@@ -896,7 +892,7 @@ run (void *cls,
       return;
     }
     GNUNET_break (0 == ntohl (rm->reserved));
-    GNUNET_CRYPTO_hash (&rm->public_key,
+    GNUNET_CRYPTO_hash (&rm->proof_of_work.key,
                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
                         &hc);
     GNUNET_break (GNUNET_OK ==
index 57234fa3681a538067d5064e2d9d0737467792fd..a57a933c36c2a6caf581a430010968a3af19a8a7 100644 (file)
@@ -134,7 +134,6 @@ block_plugin_revocation_evaluate (void *cls,
   struct InternalContext *ic = cls;
   struct GNUNET_HashCode chash;
   const struct RevokeMessage *rm = reply_block;
-  struct GNUNET_TIME_Absolute ts;
 
   if (NULL == reply_block)
     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
@@ -143,11 +142,8 @@ block_plugin_revocation_evaluate (void *cls,
     GNUNET_break_op (0);
     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
   }
-  ts = GNUNET_TIME_absolute_ntoh (rm->ts);
   if (GNUNET_YES !=
-      GNUNET_REVOCATION_check_pow (&rm->public_key,
-                                   &ts,
-                                   rm->proof_of_work,
+      GNUNET_REVOCATION_check_pow (&rm->proof_of_work,
                                    ic->matching_bits))
   {
     GNUNET_break_op (0);
@@ -155,14 +151,14 @@ block_plugin_revocation_evaluate (void *cls,
   }
   if (GNUNET_OK !=
       GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
-                                   &rm->purpose,
-                                   &rm->signature,
-                                   &rm->public_key))
+                                   &rm->proof_of_work.purpose,
+                                   &rm->proof_of_work.signature,
+                                   &rm->proof_of_work.key))
   {
     GNUNET_break_op (0);
     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
   }
-  GNUNET_CRYPTO_hash (&rm->public_key,
+  GNUNET_CRYPTO_hash (&rm->proof_of_work.key,
                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
                       &chash);
   if (GNUNET_YES ==
@@ -198,7 +194,7 @@ block_plugin_revocation_get_key (void *cls,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  GNUNET_CRYPTO_hash (&rm->public_key,
+  GNUNET_CRYPTO_hash (&rm->proof_of_work.key,
                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
                       key);
   return GNUNET_OK;
index d7b9cc139bfc46a0e5927cee1e0a43f8389e65e0..b2769da0e41da59149d671d7e0e03862df61e811 100644 (file)
@@ -27,6 +27,7 @@
 #define REVOCATION_H
 
 #include "gnunet_util_lib.h"
+#include "gnunet_revocation_service.h"
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
@@ -91,28 +92,7 @@ struct RevokeMessage
   /**
    * Number that causes a hash collision with the @e public_key.
    */
-  uint64_t proof_of_work GNUNET_PACKED;
-
-  /**
-   * Timestamp
-   */
-  struct GNUNET_TIME_AbsoluteNBO ts;
-
-  /**
-   * Signature confirming revocation.
-   */
-  struct GNUNET_CRYPTO_EcdsaSignature signature;
-
-  /**
-   * Must have purpose #GNUNET_SIGNATURE_PURPOSE_REVOCATION,
-   * size expands over the public key. (@deprecated)
-   */
-  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
-
-  /**
-   * Key to revoke.
-   */
-  struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
+  struct GNUNET_REVOCATION_Pow proof_of_work GNUNET_PACKED;
 };
 
 
index c9bb2543a2615645fd8b0b3fa853fd0ca5b9f4ef..6510f95832cc47f4e11de74f00c7495612e6b3cf 100644 (file)
@@ -51,6 +51,21 @@ struct GNUNET_REVOCATION_Query
   void *func_cls;
 };
 
+struct BestPow
+{
+  uint64_t pow;
+  unsigned int bits;
+};
+
+struct GNUNET_REVOCATION_PowCalculationHandle
+{
+  struct BestPow best[POW_COUNT];
+  struct GNUNET_REVOCATION_Pow pow;
+  uint64_t current_pow;
+  unsigned int epochs;
+  unsigned int difficulty;
+  int valid;
+};
 
 /**
  * Generic error handler, called with the appropriate
@@ -246,10 +261,7 @@ handle_revocation_response (void *cls,
  */
 struct GNUNET_REVOCATION_Handle *
 GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                          const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
-                          const struct GNUNET_CRYPTO_EcdsaSignature *sig,
-                          const struct GNUNET_TIME_Absolute *ts,
-                          uint64_t pow,
+                          const struct GNUNET_REVOCATION_Pow *pow,
                           GNUNET_REVOCATION_Callback func,
                           void *func_cls)
 {
@@ -272,9 +284,7 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                               "WORKBITS",
                                               &matching_bits)) &&
       (GNUNET_YES !=
-       GNUNET_REVOCATION_check_pow (key,
-                                    ts,
-                                    pow,
+       GNUNET_REVOCATION_check_pow (pow,
                                     (unsigned int) matching_bits)))
   {
     GNUNET_break (0);
@@ -297,12 +307,7 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
   env = GNUNET_MQ_msg (rm,
                        GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
   rm->reserved = htonl (0);
-  rm->proof_of_work = pow;
-  rm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
-  rm->purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
-                            + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
-  rm->public_key = *key;
-  rm->signature = *sig;
+  rm->proof_of_work = *pow;
   GNUNET_MQ_send (h->mq,
                   env);
   return h;
@@ -344,6 +349,23 @@ count_leading_zeroes (const struct GNUNET_HashCode *hash)
 }
 
 
+/**
+ * Calculate the average zeros in the pows.
+ *
+ * @param ph the PowHandle
+ * @return the average number of zeroes.
+ */
+static unsigned int
+calculate_score (const struct GNUNET_REVOCATION_PowCalculationHandle *ph)
+{
+  double sum = 0.0;
+  for (unsigned int j = 0; j<POW_COUNT; j++)
+    sum += ph->best[j].bits;
+  double avg = sum / POW_COUNT;
+  return avg;
+}
+
+
 /**
  * Check if the given proof-of-work value
  * would be acceptable for revoking the given key.
@@ -355,32 +377,133 @@ count_leading_zeroes (const struct GNUNET_HashCode *hash)
  * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
  */
 int
-GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
-                             const struct GNUNET_TIME_Absolute *ts,
-                             uint64_t pow,
-                             unsigned int matching_bits)
+GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_Pow *pow,
+                             unsigned int difficulty)
+{
+  char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
+           + sizeof (uint64_t)
+           + sizeof (uint64_t)] GNUNET_ALIGN;
+  struct GNUNET_HashCode result;
+  unsigned int score = 0;
+  unsigned int tmp_score = 0;
+  unsigned int epochs;
+  uint64_t pow_val;
+
+  GNUNET_memcpy (&buf[sizeof(uint64_t)],
+                 &pow->timestamp,
+                 sizeof (uint64_t));
+  GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
+                 &pow->key,
+                 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
+  for (unsigned int i = 0; i < POW_COUNT; i++)
+  {
+    pow_val = GNUNET_ntohll (pow->pow[i]);
+    GNUNET_memcpy (buf, &pow_val, sizeof(uint64_t));
+    GNUNET_CRYPTO_pow_hash ("gnunet-revocation-proof-of-work",
+                            buf,
+                            sizeof(buf),
+                            &result);
+    tmp_score = count_leading_zeroes (&result);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Score %u (#%u)\n",
+                tmp_score, i);
+    score += tmp_score;
+
+  }
+  score = score / POW_COUNT;
+  if (score < difficulty)
+    return GNUNET_NO;
+  // TODO verfiy signature?
+  epochs = score - difficulty + 1;
+  // TODO verify expiration
+  return GNUNET_YES;
+}
+
+
+struct GNUNET_REVOCATION_PowCalculationHandle*
+GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
+                            int epochs,
+                            unsigned int difficulty)
+{
+  struct GNUNET_REVOCATION_PowCalculationHandle*pc;
+  struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get();
+
+  pc = GNUNET_new (struct GNUNET_REVOCATION_PowCalculationHandle);
+  pc->pow.key = *key;
+  pc->pow.timestamp = GNUNET_TIME_absolute_hton(ts);
+  pc->current_pow = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                              UINT64_MAX);
+  pc->difficulty = difficulty;
+  pc->epochs = epochs;
+  return pc;
+}
+
+
+/**
+ * Calculate a key revocation valid for broadcasting for a number
+ * of epochs.
+ *
+ * @param pc handle to the PoW, initially called with NULL.
+ * @param epochs number of epochs for which the revocation must be valid.
+ * @param pow current pow value to try
+ * @param difficulty current base difficulty to achieve
+ * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
+ */
+int
+GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
 {
   char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
-           + sizeof(pow)
-           + sizeof (struct GNUNET_TIME_AbsoluteNBO)] GNUNET_ALIGN;
+           + sizeof (uint64_t)
+           + sizeof (uint64_t)] GNUNET_ALIGN;
   struct GNUNET_HashCode result;
-  struct GNUNET_TIME_AbsoluteNBO ts_nbo;
+  unsigned int zeros;
 
-  ts_nbo = GNUNET_TIME_absolute_hton (*ts);
+  pc->current_pow++;
 
-  GNUNET_memcpy (buf, &pow, sizeof(pow));
-  GNUNET_memcpy (&buf[sizeof(pow)],
-                 &ts_nbo,
-                 sizeof (struct GNUNET_TIME_AbsoluteNBO));
-  GNUNET_memcpy (&buf[sizeof(pow) + sizeof (struct GNUNET_TIME_AbsoluteNBO)],
-                 key,
+  GNUNET_memcpy (buf, &pc->current_pow, sizeof(uint64_t));
+  GNUNET_memcpy (&buf[sizeof(uint64_t)],
+                 &pc->pow.timestamp,
+                 sizeof (uint64_t));
+  GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
+                 &pc->pow.key,
                  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
   GNUNET_CRYPTO_pow_hash ("gnunet-revocation-proof-of-work",
                           buf,
                           sizeof(buf),
                           &result);
-  return (count_leading_zeroes (&result) >=
-          matching_bits) ? GNUNET_YES : GNUNET_NO;
+  zeros = count_leading_zeroes (&result);
+  for (unsigned int i = 0; i < POW_COUNT; i++)
+  {
+    if (pc->best[i].bits < zeros)
+    {
+      pc->best[i].bits = zeros;
+      pc->best[i].pow = pc->current_pow;
+      pc->pow.pow[i] = GNUNET_htonll (pc->current_pow);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "New best score %u (#%u)\n",
+                  zeros, i);
+      break;
+    }
+  }
+  return calculate_score (pc) >= pc->difficulty + pc->epochs ? GNUNET_YES :
+         GNUNET_NO;
+}
+
+
+const struct GNUNET_REVOCATION_Pow*
+GNUNET_REVOCATION_pow_get (const struct
+                           GNUNET_REVOCATION_PowCalculationHandle *pc)
+{
+  return calculate_score (pc) >= pc->difficulty + pc->epochs ? &pc->pow :
+         NULL;
+}
+
+
+void
+GNUNET_REVOCATION_pow_cleanup (struct
+                               GNUNET_REVOCATION_PowCalculationHandle *pc)
+{
+  GNUNET_free (pc);
 }
 
 
@@ -391,20 +514,17 @@ GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
  * @param sig where to write the revocation signature
  */
 void
-GNUNET_REVOCATION_sign_revocation (const struct
-                                   GNUNET_CRYPTO_EcdsaPrivateKey *key,
-                                   struct GNUNET_CRYPTO_EcdsaSignature *sig)
+GNUNET_REVOCATION_sign_revocation (struct GNUNET_REVOCATION_Pow *pow,
+                                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *key)
 {
-  struct RevokeMessage rm;
-
-  rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
-  rm.purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
+  pow->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
+  pow->purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
                            + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
-  GNUNET_CRYPTO_ecdsa_key_get_public (key, &rm.public_key);
+  GNUNET_CRYPTO_ecdsa_key_get_public (key, &pow->key);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CRYPTO_ecdsa_sign_ (key,
-                                            &rm.purpose,
-                                            sig));
+                                            &pow->purpose,
+                                            &pow->signature));
 }