]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Remove minor biasing problem from crypto_pseudo_rand_int
authorNick Mathewson <nickm@torproject.org>
Wed, 12 Nov 2003 04:28:30 +0000 (04:28 +0000)
committerNick Mathewson <nickm@torproject.org>
Wed, 12 Nov 2003 04:28:30 +0000 (04:28 +0000)
svn:r799

src/common/crypto.c
src/common/crypto.h

index afec91d22d940ee5ae70e7a1fbc38b7aed3a4ff0..551af896429f2cf1caae30f910edc209de6902af 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
+#include <limits.h>
 
 #include "crypto.h"
 #include "../or/or.h"
@@ -1008,14 +1009,21 @@ 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;
-  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).
-   **/
-  return val % max;
+  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);
+    if (val < cutoff)
+      return val % max;
+  }
 }
 
 /* errors */
index ab5422d8cdf9e817d57520d1bd92ed68c84673fd..0d8257fd9c9d1421d46d4fae0473f4b44c97ef23 100644 (file)
@@ -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();