web-dev-qa-db-fra.com

Correc façon d'obtenir un numéro de 0 à 9 d'un octet aléatoire?

Si j'ai un bon générateur de nombres aléatoires qui me donne un octet de données à la fois, et je souhaite extraire un chiffre décimal aléatoire de 0 à 9 de ce flux d'octets, quelle est la bonne façon de faire cela?

Au début, je suppose naïvement qu'un calcul simple (RandomByte Mod 10) serait suffisant, mais depuis 256 n'est pas uniformément divisible de 10, ce qui entraîne un biais clair dans les chiffres "aléatoires":

0: 101323 #################################
1: 101261 #################################
2: 101473 #################################
3: 101389 #################################
4: 101551 #################################
5: 101587 #################################
6: 97831  ###############################
7: 97893  ###############################
8: 97843  ###############################
9: 97849  ###############################
(histogram from 1 million 'random' digits)

Une méthode qui semble fonctionner est de supprimer toute valeur supérieure à 249 et diviser par 25. Est-ce que Cryptographiquement correct? Existe-t-il une meilleure méthode qui n'implique pas de jeter (potentiellement coûteux) d'octets de caractère aléatoire?

(cette question est invitée à lire sur une vulnérabilité de cryptocat , où l'un des défauts découverts était qu'ils ont jeté des valeurs aléatoires supérieures à 250 au lieu de 249, donnant une légère Biais dans leurs numéros "aléatoires" ... alors j'étais curieux ce que le "bon" moyen de le faire est)

16
Johnny

Il existe deux manières génériques de produire un chiffre aléatoire "suffisamment impartial".

Première méthode est de boucler si l'octet n'était pas dans la bonne plage. C'est à dire.:

  • Obtenez la prochaine octet aléatoire B.
  • Si B est dans la plage 0..249, renvoie B MOD 10.
  • Boucle.

Cette méthode peut consommer un nombre non lié d'octets aléatoires, mais il est parfaitement impartial et il est très peu probable qu'il nécessite une boucle plusieurs fois. C'est ce que Java aléatoire.nextint (int) La méthode standard s'applique (bien que des mots 32 bits au lieu d'octets).

Deuxième méthode est d'utiliser comme valeur source non encline octet mais un mot assez grand. Dis, utilisez 20 octets, interprétez ceux-ci comme un entier x dans le 0..2160-1 Plage et retour x MOD 10. De cette façon, le biais est toujours là, mais peut être fait arbitrairement petit, au point que cela ne compte plus. Ceci est calculé en calcul (plus que la première méthode), mais a l'avantage de toujours exiger le même nombre d'octets d'entrée, qui peuvent être utiles dans certaines situations spécifiques (par exemple, des fuites de canal latéral).

16
Tom Leek

Vous pouvez le faire de deux manières.

Le premier est de diviser l'octet en deux nombres de 4 bits. Si le nombre à 4 bits est supérieur à 9, jetez-le. Vous pouvez obtenir jusqu'à 2 chiffres par octet de cette façon.

Une autre façon que vous puissiez faire cela est si elle est de moins de 200 ans, prenez les deux derniers chiffres. Ensuite, vous avez 2 chiffres aléatoires. Si c'est moins de 250, prenez le dernier chiffre. Si c'est au-dessus de 250, jetez-le. De cette façon, vous pouvez obtenir les chiffres les plus aléatoires de votre numéro.

1
Spl1ce