Commit 5e4b9c6b authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Remove minor biasing problem from crypto_pseudo_rand_int


svn:r799
parent 7e4cb9a7
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <limits.h>

#include "crypto.h"
#include "../or/or.h"
@@ -1008,15 +1009,22 @@ void crypto_pseudo_rand(unsigned int n, unsigned char *to)
  }
}

int crypto_pseudo_rand_int(int max) {
int crypto_pseudo_rand_int(unsigned int max) {
  unsigned int val;
  unsigned int cutoff;
  assert(max < UINT_MAX);

  /* We ignore any values that are >= 'cutoff,' to avoid biasing the
   * distribution with clipping at the upper end of unsigned int's
   * range.
   */
  cutoff = UINT_MAX - (UINT_MAX%max);
  while(1) {
    crypto_pseudo_rand(sizeof(val), (unsigned char*) &val);
  /* Bug: Low values are _slightly_ favored over high values because
   * ((unsigned)-1)%max != max-1 .  This shouldn't matter if max is
   * significantly smaller than ((unsigned)-1).
   **/
    if (val < cutoff)
      return val % max;
  }
}

/* errors */
char *crypto_perror()
+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ int crypto_SHA_digest(unsigned char *m, int len, unsigned char *digest);
int crypto_seed_rng();
int crypto_rand(unsigned int n, unsigned char *to);
void crypto_pseudo_rand(unsigned int n, unsigned char *to);
int crypto_pseudo_rand_int(int max);
int crypto_pseudo_rand_int(unsigned int max);

/* errors */
char *crypto_perror();