SHISHUA: le générateur de nombres pseudo-aléatoires le plus rapide au monde


Il y a six mois, je voulais créer le meilleur générateur de nombres pseudo-aléatoires (PRNG) avec une architecture inhabituelle. Je pensais que le début serait facile et que vous travaillez, la tùche deviendra lentement plus complexe. Et j'ai pensé que si je pouvais tout apprendre assez rapidement pour faire face aux plus difficiles.

À ma grande surprise, la complexitĂ© n'a pas augmentĂ© de façon linĂ©aire. Les tests d'octets chi carrĂ© se sont rĂ©vĂ©lĂ©s trĂšs difficiles! Plus tard, il a Ă©tĂ© tout aussi difficile de passer des tests inflexibles. J'ai publiĂ© les rĂ©sultats actuels pour comprendre quelles autres difficultĂ©s m'attendent. Cependant , le test PractRand a Ă©chouĂ© Ă  ce moment-lĂ  .

Ensuite, il a été trÚs difficile de réussir le test BigCrush .

Ensuite, il était trÚs difficile de transférer 32 téraoctets de données lors du passage de PractRand. La vitesse est devenue un problÚme. Il ne suffit pas de créer un design qui génÚre dix mégaoctets par seconde, car passer PractRand prendrait un mois. Mais je dois admettre qu'il était trÚs difficile de passer ce test à une vitesse de gigaoctets par seconde .

Lorsque vous montez à une telle hauteur ... vous voulez savoir si vous pouvez vous rendre à la frontiÚre de Pareto. Vous voulez créer le PRNG le plus rapide au monde, qui passera les tests statistiques les plus complexes.

J'ai réussi.

Dans un article précédent, j'ai parlé de ce que j'ai appris pour atteindre mon objectif. Et ici, je vais vous dire comment fonctionne l'architecture finale.

objectif


Commençons par l'évidence: la vitesse dépend de la plateforme . Je me suis concentré sur l'optimisation de l'architecture x86-64 moderne (processeurs Intel et AMD).

Pour comparer les performances, la mĂ©trique cpb classique est utilisĂ©e : il s'agit du nombre de cycles de processeur dĂ©pensĂ©s pour gĂ©nĂ©rer un octet. Cette mĂ©trique est calculĂ©e et comparĂ©e dans toutes les Ɠuvres cryptographiques. Un cpb lĂ©gĂšrement infĂ©rieur dans le monde du logiciel ou du matĂ©riel peut assurer la victoire dans la compĂ©tition ou l'utilisation sur des sites Web Ă  travers le monde.

Pour améliorer cpb, vous pouvez:

  1. GĂ©nĂ©rez plus d'octets avec la mĂȘme quantitĂ© de travail,
  2. Ou faites moins de travail pour gĂ©nĂ©rer le mĂȘme nombre d'octets,
  3. Ou parallélisez le travail.

Nous ferons tout ce qui précÚde.

Selon le premier point, nous devons produire plus de bits à chaque itération.

J'avais peur qu'on me dise: "S'il ne donne pas de numĂ©ros 32 bits, alors ce n'est pas le DSRP", ou la mĂȘme chose avec des numĂ©ros 64 bits. Ou: "Le PRNG ne devrait ĂȘtre que pour l'architecture x86-64", comme si les instructions comme POPCNT ou les registres comme% xmm7 Ă©taient interdits.

Cependant, le PRNG est une ingĂ©nierie: les gĂ©nĂ©rateurs tentent depuis plusieurs dĂ©cennies de tirer tout ce qui est possible des processeurs! Lorsque ROL est apparu, ils ont commencĂ© Ă  compter sur lui. Avec l'avĂšnement des processeurs 64 bits, ils ont commencĂ© Ă  s'appuyer sur% rax. Bien sĂ»r, sur ARM, ces algorithmes peuvent fonctionner plus lentement (bien que cela reste Ă  voir), cependant, les PRN 64 bits Ă©taient activement utilisĂ©s avant mĂȘme que Android ne commence Ă  nĂ©cessiter la prise en charge du 64 bits en 2019!

Autrement dit, ce domaine se développe avec le matériel. Et aujourd'hui, les processeurs Intel et AMD dus à AVX2 prennent déjà en charge les opérations 256 bits. RC4 a produit 1 octet, drand48 pourrait produire 4 octets à la fois, pcg64 - 8 octets, et maintenant nous pouvons immédiatement générer 32 octets.

8 octets peuvent ĂȘtre un nombre 64 bits, et la plupart des langages de programmation ont des types intĂ©grĂ©s pour cela. Mais peu de langues fournissent des types pour 16 octets (une exception notable est __uint128_t en C). Encore moins de langues ont du type pour 32 octets (sauf internes).

On peut donc dire adieu au prototype habituel de la fonction PRNG (exemple du benchmark Vigny HWD ):

static uint64_t next(void);

Au lieu de cela, vous pouvez créer un générateur qui remplit le tampon (exemple de mon benchmark ):

void prng_gen(prng_state *s, __uint64_t buf[], __uint64_t size);

Quels sont les inconvénients de cette solution?

Si votre générateur produit 32 octets à la fois, vous devez fournir au consommateur un tableau qui est un multiple de 32 (idéalement aligné sur 32 octets). Bien que vous puissiez vous en passer, nous allons simplement remplir le tampon. Nous allons supprimer les données inutilisées et les remplir à nouveau si nécessaire. Le délai devient imprévisible: certains appels ne feront que lire le tampon. Mais en moyenne, tout sera pareil.

Nous gĂ©nĂ©rons maintenant plus d'octets, effectuant la mĂȘme quantitĂ© de travail. Comment la parallĂ©lisons-nous?

Parallélisme


Les processeurs offrent un ensemble incroyable d'outils de parallélisation à tous les niveaux.

Tout d'abord, ce sont des instructions SIMD (Single-Instruction, Multiple Data). Par exemple, AVX2 effectue simultanément quatre ajouts 64 bits, ou huit ajouts 32 bits, etc.

Il est utilisé en cryptographie depuis une quinzaine d'années. La concurrence a fourni les performances incroyables du ChaCha20 . Il est utilisé par les primitives les plus importantes qui n'utilisent pas AESNI. Par exemple, NORX et Gimli sont conçus avec le parallélisme à l'esprit.

RĂ©cemment, l'intĂ©rĂȘt pour ce sujet a Ă©galement augmentĂ© dans la communautĂ© PRNG non cryptographique. En particulier, les primitives existantes qui n'ont pas Ă©tĂ© conçues pour SIMD peuvent ĂȘtre Ă  la base de la crĂ©ation de PRN trĂšs rapides.

Lorsque Sebastiano Vigna a fait la promotion de son architecture xoshiro256 ++ dans la bibliothĂšque standard Julia, il a dĂ©couvert que les rĂ©sultats de huit instances PRNG compĂ©titives et initialisĂ©es diffĂ©remment peuvent ĂȘtre concatĂ©nĂ©es trĂšs rapidement si chaque opĂ©ration est effectuĂ©e simultanĂ©ment dans tous les PRNR.

SIMD n'est qu'un des niveaux de parallélisation du processeur. Je recommande de lire l' article précédent sur ce sujet afin d'avoir une meilleure idée, mais je vais donner quelques explications.

Les pipelines de processeurs permettent de traiter plusieurs instructions à différentes étapes. Si vous organisez bien l'ordre de leur exécution afin de réduire les dépendances entre les étapes, vous pouvez accélérer le traitement des instructions.

L'exĂ©cution superscalaire vous permet de traiter simultanĂ©ment les parties informatiques des instructions. Mais pour cela, ils ne devraient pas avoir de dĂ©pendances en lecture-Ă©criture. Vous pouvez adapter l'architecture pour rĂ©duire le risque de temps d'arrĂȘt en enregistrant bien avant la lecture.

Une exĂ©cution extraordinaire permet au processeur d'exĂ©cuter des instructions non pas dans l'ordre de sĂ©quence, mais lorsqu'elles sont prĂȘtes, mĂȘme si les instructions prĂ©cĂ©dentes ne sont pas encore prĂȘtes. Mais pour cela, il ne devrait pas y avoir de dĂ©pendance en lecture-Ă©criture.

Et maintenant, nous passons à la mise en Ɠuvre!

Architecture


Considérons un schéma appelé semi-SHISHUA. La provenance d'un tel nom deviendra progressivement apparente à mesure que vous lirez.

Le schéma ressemble à ceci:


Considérez sa ligne par ligne.

typedef struct prng_state {
  __m256i state[2];
  __m256i output;
  __m256i counter;
} prng_state;

L'Ă©tat est divisĂ© en deux parties, qui sont placĂ©es dans le registre AVX2 (256 bits). Pour augmenter la vitesse, nous gardons le rĂ©sultat proche de l'Ă©tat lui-mĂȘme, mais il ne fait pas partie de l'Ă©tat.

Nous avons Ă©galement un compteur 64 bits. Pour simplifier le calcul, c'est aussi un registre AVX2. Le fait est que AVX2 a une petite fonctionnalitĂ©: les registres ordinaires (% rax et similaires) ne peuvent pas ĂȘtre transfĂ©rĂ©s directement vers SIMD via MOV, ils doivent passer par la RAM (le plus souvent via la pile), ce qui augmente le dĂ©lai et coĂ»te deux instructions de processeur (MOV sur la pile, VMOV de la pile).

Voyons maintenant la génération. Commençons par charger, puis parcourons le tampon et remplissons-le avec 32 octets à chaque itération.

inline void prng_gen(prng_state *s, __uint64_t buf[], __uint64_t size) {
  __m256i s0 = s->state[0], counter = s->counter,
          s1 = s->state[1],       o = s->output;
  for (__uint64_t i = 0; i < size; i += 4) {
    _mm256_storeu_si256((__m256i*)&buf[i], o);
    // 

  }
  s->state[0] = s0; s->counter = counter;
  s->state[1] = s1; s->output  = o;
}

Puisque la fonction est en ligne, le remplissage immédiat du tampon au démarrage permet au processeur d'exécuter immédiatement les instructions en fonction de cela grùce à un mécanisme d'exécution extraordinaire.

À l'intĂ©rieur de la boucle, nous effectuons rapidement trois opĂ©rations d'Ă©tat:

  1. SHI ft
  2. SHU ffle
  3. Un dd

D'oĂč le nom SHISHUA!

Premier quart de travail


u0 = _mm256_srli_epi64(s0, 1);              u1 = _mm256_srli_epi64(s1, 3);

Malheureusement, l'AVX2 ne prend pas en charge les révolutions. Mais je veux mélanger les bits d'une position dans un nombre 64 bits avec les bits d'une autre position! Et le changement est le meilleur moyen de réaliser cela. Nous allons décaler d'un nombre impair, de sorte que chaque bit visite toutes les positions 64 bits, et non la moitié d'entre elles.

Pendant le quart de travail, des bits sont perdus, ce qui entraßne la suppression d'informations de notre état. C'est mauvais, vous devez minimiser les pertes. Les plus petits nombres impairs sont 1 et 3, nous utiliserons différentes valeurs de décalage pour augmenter l'écart entre les deux parties. Cela aidera à réduire la similitude de leur auto-corrélation.

Nous allons déplacer vers la droite, car les bits les plus à droite ont la diffusion la plus faible lors de l'addition: par exemple, le bit le moins significatif dans A + B est juste le XOR des bits les moins significatifs A et B.

En remuant


t0 = _mm256_permutevar8x32_epi32(s0, shu0); t1 = _mm256_permutevar8x32_epi32(s1, shu1);

Nous utiliserons le mixage 32 bits, car cela donne une granularité différente par rapport aux opérations 64 bits que nous utilisons partout (l'alignement 64 bits est violé). Il peut également s'agir d'une opération transversale: d'autres shuffles peuvent déplacer des bits dans les 128 bits à gauche s'ils commencent à gauche, ou dans les 128 bits à droite s'ils commencent à droite.

MĂ©lange de constantes:

__m256i shu0 = _mm256_set_epi32(4, 3, 2, 1, 0, 7, 6, 5),
        shu1 = _mm256_set_epi32(2, 1, 0, 7, 6, 5, 4, 3);

Pour que le mélange améliore vraiment le résultat, nous déplacerons les parties 32 bits faibles (faible dispersion) des ajouts 64 bits vers des positions fortes, de sorte que les ajouts suivants les enrichissent.

La partie 32 bits bas de gamme du bloc 64 bits ne se dĂ©place jamais vers le mĂȘme bloc 64 bits que la partie d'ordre supĂ©rieur. Ainsi, les deux parties ne restent pas dans le mĂȘme morceau, ce qui amĂ©liore le mĂ©lange.

Au final, chaque partie 32 bits passe par toutes les positions d'un cercle: de A Ă  B, de B Ă  C, ... de H Ă  A.

Vous avez peut-ĂȘtre remarquĂ© que le mixage le plus simple qui prend en compte toutes ces exigences est deux 256 bits chiffre d'affaires (tours de 96 bits et 160 bits Ă  droite, respectivement).

Une addition


Ajoutons des morceaux 64 bits à partir de deux variables temporaires - décalage et mixage.

s0 = _mm256_add_epi64(t0, u0);              s1 = _mm256_add_epi64(t1, u1);

L'addition est la principale source de dispersion: dans cette opération, les bits sont combinés en combinaisons irréductibles d'expressions XOR et AND réparties sur des positions 64 bits.

Le stockage du résultat de l'addition dans un état préserve durablement cette dispersion.

Fonction de sortie


D'oĂč tirons-nous la sortie?

C'est simple: la structure que nous avons créée nous permet de générer deux parties indépendantes de l'état s0 et s1, qui ne s'affectent en aucune façon. Appliquez XOR sur eux et obtenez un résultat complÚtement aléatoire.

Pour renforcer l'indépendance entre les données auxquelles nous appliquons XOR, nous prenons un résultat partiel: la partie décalée d'un état et la partie mixte d'un autre.

o = _mm256_xor_si256(u0, t1);

Cela revient Ă  rĂ©duire les dĂ©pendances en lecture-Ă©criture entre les instructions d'un processeur superscalaire, comme si u0 et t1 Ă©taient prĂȘts Ă  lire en s0 et s1.

Maintenant, discutez du compteur. Nous le traitons au début du cycle. Tout d'abord, modifiez l'état, puis augmentez la valeur du compteur:

s1 = _mm256_add_epi64(s1, counter);
counter = _mm256_add_epi64(counter, increment);

Pourquoi changeons-nous d'abord l'Ă©tat, puis mettons Ă  jour le compteur? s1 devient disponible plus tĂŽt, ce qui rĂ©duit la probabilitĂ© que les instructions suivantes qui le lisent s'arrĂȘtent dans le pipeline du processeur. De plus, cette sĂ©quence permet d'Ă©viter la dĂ©pendance directe du compteur de lecture-Ă©criture.

Nous appliquons le compteur à s1, et non à s0, car ils affectent tous les deux la sortie de toute façon, cependant, s1 perd plus de bits en raison du décalage, de sorte qu'il l'aide à «se remettre sur pied» aprÚs le décalage.

Le compteur peut ne pas enregistrer le test PractRand. Son seul objectif est de fixer une limite inférieure de 2 69octets = 512 exbibytes pour la période PRNG: on ne recommence le cycle qu'aprÚs un millénaire de travail à une vitesse de 10 gibytes par seconde. Il est peu probable qu'il soit trop lent pour une utilisation pratique dans les siÚcles à venir.

Incrément:

__m256i increment = _mm256_set_epi64x(1, 3, 5, 7);

Les nombres impairs sont sélectionnés comme incréments, car seuls les nombres premiers de base couvrent tout le cycle du champ fini GF (2 64 ), et tous les nombres impairs sont premiers de 2. En d'autres termes, si vous incrémentez d'un entier pair dans la plage de 0 à 4, revenant à 0 aprÚs 4, il s'avÚre que la séquence 0-2-0-2- ..., qui ne conduira jamais à 1 ou 3. Et l'incrément impair passe par tous les entiers.

Pour tous les nombres 64 bits en état, nous utiliserons des nombres impairs différents, ce qui les séparera davantage et augmentera légÚrement le mélange. J'ai choisi les plus petits nombres impairs pour qu'ils n'aient pas l'air magique.

C'est ainsi que la transition d'Ă©tat et la fonction de sortie fonctionnent. Comment les initialiser?

Initialisation


Nous initialisons l'état en utilisant les chiffres hexadécimaux Ί, le nombre irrationnel le moins approximé par la fraction.

static __uint64_t phi[8] = {
  0x9E3779B97F4A7C15, 0xF39CC0605CEDC834, 0x1082276BF3A27251, 0xF86C6A11D0C18E95,
  0x2767F0B153D27B7F, 0x0347045B5BF1827F, 0x01886F0928403002, 0xC1D64BA40F335E36,
};

Prenez une graine 256 bits. Cela se fait souvent en cryptographie et ne nuit pas au travail des PRNG non cryptographiques:

prng_state prng_init(SEEDTYPE seed[4]) {
  prng_state s;
  // 

  return s;
}

Nous ne voulons pas redéfinir toute la partie de l'état (s0 ou s1) avec ce nombre initial, il suffit d'en affecter la moitié. De cette façon, nous éviterons l'utilisation de nombres initiaux atténuants, qui provoquent accidentellement ou intentionnellement un état initial faible connu.

Comme nous ne modifions pas la moitié de chaque état, nous gardons le contrÎle sur 128 bits d'état. Une telle entropie est suffisante pour démarrer et maintenir une position forte.

s.state[0] = _mm256_set_epi64x(phi[3], phi[2] ^ seed[1], phi[1], phi[0] ^ seed[0]);
s.state[1] = _mm256_set_epi64x(phi[7], phi[6] ^ seed[3], phi[5], phi[4] ^ seed[2]);

Ensuite, nous répétons ( ROUNDS) plusieurs fois la séquence suivante:

  1. Exécutez les étapes ( STEPS) des itérations SHISHUA.
  2. Nous attribuons une partie de l'Ă©tat Ă  un autre Ă©tat et l'autre partie Ă  la sortie.

for (char i = 0; i < ROUNDS; i++) {
  prng_gen(&s, buf, 4 * STEPS);
  s.state[0] = s.state[1];
  s.state[1] = s.output;
}

L'attribution d'un résultat de sortie augmente la dispersion des états. Lors de l'initialisation, le travail supplémentaire et la corrélation des états n'ont pas d'importance, car cette série d'opérations est effectuée une seule fois. Nous ne nous intéressons qu'à la dispersion lors de l'initialisation.

AprÚs avoir évalué l'effet sur la corrélation des valeurs initiales, j'ai choisi STEPS2 pour la valeur et ROUNDS10 pour 10. J'ai calculé la corrélation en calculant les anomalies «inhabituelles» et «suspectes» résultant des outils de contrÎle qualité PRNG dans PractRand.

Performance


Il est difficile de mesurer la vitesse pour plusieurs raisons:

  • La mesure de l'horloge n'est peut-ĂȘtre pas suffisamment prĂ©cise.
  • , , - , -, .
  • , . .
  • : , .

J'utilise l'instruction du processeur RDTSC, qui calcule le nombre de cycles.

Pour que tout le monde puisse reproduire mes rĂ©sultats, j'utilise une machine virtuelle basĂ©e sur le cloud. Cela ne change pas le niveau des rĂ©sultats de rĂ©fĂ©rence par rapport aux tests locaux. De plus, vous n'avez pas Ă  acheter le mĂȘme ordinateur que le mien. Enfin, il existe de nombreuses situations oĂč le PRNG est lancĂ© dans les nuages.

J'ai choisi Google Cloud Platform N2 (processeur Intel) et N2D (processeur AMD). L'avantage de GCP est qu'il propose des serveurs avec des processeurs des deux fabricants. Dans cet article, nous nous concentrerons sur Intel, mais pour AMD, les rĂ©sultats seront dans le mĂȘme ordre.

Pour approfondir le sujet, débarrassons-nous d'abord de l'ancien générateur cryptographique RC4. Impossible de paralléliser le travail, j'ai7,5 cpb (cycles par octet généré).

Maintenant, exécutons un MCG trÚs populaire et rapide: le Lehmer128 PRNG le plus simple , qui réussit le test BigCrush, a montré 0,5 cpb . Wow, super!

Ensuite, nous exécuterons le dernier développement, qui est utilisé pour les tables de hachage rapides - wyrand . 0,41 cpb , un peu mieux!

Certains DSRP ne réussissent pas le test PractRand de 32 téraoctets, mais ils fonctionnent trÚs rapidement. Xoshiro256 + n'a atteint que 512 mégaoctets, mais a montré une vitesse trÚs élevée: 0,34 cpb .

Un autre dĂ©veloppement rĂ©cent de RomuTrio . Elle prĂ©tend ĂȘtre le PRNG le plus rapide au monde - 0,31 cpb.

D'accord, ça suffit. Qu'est-ce que le semi-SHISHUA a montré?

0,14 cpb . Deux fois plus vite que RomuTrio.


Cool. Testez maintenant le générateur cryptographique ChaCha8. Il a atteint ... 0,12 cpb .

Oh.

SIMD est une vraie magie!

Pour la communautĂ© cryptographique, ce n'Ă©tait pas une surprise particuliĂšre . ChaCha8 est extrĂȘmement facile Ă  parallĂ©liser. Ceci est juste un compteur bien hachĂ© dans un Ă©tat diffus.

Et vous vous souvenez comment l'équipe linguistique de Julia a essayé de combiner plusieurs instances de l'architecture de Vigny pour créer un PRNG rapide basé sur SIMD? Regardons leur résultat en utilisant cette technique ( 8 piÚces de Xoshiro256 + ). 0,09 cpb !

Techniquement, mon ordinateur portable pourrait affecter les résultats. Je ne sais pas pourquoi le développement de l'équipe Julia est plus rapide que ChaCha8 dans GCP, mais plus lent lorsqu'il est testé localement. Sur ma machine, semi-SHISHUA tourne plus vite que le développement de l'équipe Julia, mais plus lentement que ChaCha8.

Il est nécessaire de vaincre tous les concurrents.

Vous vous demandez probablement déjà pourquoi nous avons appelé la version précédente du générateur semi-SHISHUA? Parce qu'il s'est avéré facile de doubler la vitesse si vous exécutez deux copies de semi-SHISHUA.

Semblable à l'idée de la commande Julia, nous initialisons séparément deux PRNG (quatre blocs d'un état 256 bits), fournissant alternativement la sortie de leur travail.

Mais si nous créons plus d'états, nous pouvons produire encore plus de données, en combinant quatre états par paires:

o0 = _mm256_xor_si256(u0, t1);
o1 = _mm256_xor_si256(u2, t3);
o2 = _mm256_xor_si256(s0, s3);
o3 = _mm256_xor_si256(s2, s1);

Nous avons donc obtenu SHISHUA, qui a montré une vitesse de 0,06 cpb .

C'est deux fois plus rapide que le précédent concurrent le plus rapide au monde qui a réussi le test PractRand de 32 téraoctets. Le résultat est sur le graphique.

Je pense que le développement s'est révélé compétitif. Cela fonctionne encore plus rapidement sur mon ordinateur portable - 0,03 cpb, mais je respecterai mes principes concernant le benchmark.

J'espÚre que pendant quelques semaines encore mon générateur restera sur le podium des plus rapides du monde (veuillez le faire).

Qualité


Le gĂ©nĂ©rateur passe honnĂȘtement BigCrush et le test PractRand de 32 tĂ©raoctets. Et tout cela grĂące Ă  quatre flux de sortie.

Les inconvĂ©nients de l'architecture incluent son irrĂ©versibilitĂ© . Cela peut ĂȘtre vu en rĂ©duisant Ă  un Ă©tat 4 bits avec s0 = [a, b]et s1 = [c, d]. Avec un dĂ©calage, nous obtenons [0, a]et [0, d], et en remuant, [b, c]et [d, a]. De nouveaux s0Ă©gaux [b, c] + [0, a] = [b⊕(a∧c), a⊕c], mais s1Ă©gaux [d, a] + [0, c] = [d⊕(a∧c), a⊕c]. Si a = ÂŹc, alors, a⊕c = 1et a∧c = 0donc, s0 = [b, 1]et s1 = [d, 1]. Autrement dit, nous obtenons deux combinaisons de aet c, qui nous donnent le mĂȘme Ă©tat final.

Dans notre cas, ce n'est pas un problĂšme, car le compteur 64 bits fait Ă©galement partie de l'Ă©tat. Il s'avĂšre que le cycle minimum de 2 71octets (128 octets par transition d'Ă©tat), ce qui est Ă  une vitesse de 10 gibytes / sec. durera sept mille ans. Cela Ă©quilibre les Ă©tats perdus.

De plus, mĂȘme malgrĂ© l'irrĂ©versibilitĂ©, la pĂ©riode de transition moyenne entre les États est de 2 ^ ((256 + 1) Ă· 2). Cela donne un cycle moyen de 2 135 octets (Ă  une vitesse de 10 gibytes / sec. Il durera plus d'un billion de fois plus longtemps que l'univers n'existe). MĂȘme si je crois que les cycles intermĂ©diaires sont surestimĂ©s, car ils ne nous disent rien sur la qualitĂ© du gĂ©nĂ©rateur.

Voici les résultats de référence:

GénérateurPerformanceQualitéCorrélation des semences
SHISHUA0,06> 32 TiB> 256 Gio
xoshiro256 + x80,091 Kio0 Kio
ChaCha80,12> 32 TiB?> 32 TiB?
RomuTrio0,31> 32 TiB1 Kio
xoshiro256 +0,34512 Mio1 Kio
wyrand0,41> 32 TiB8 Kio
Lehmer1280,44> 32 TiB1 Kio
RC47.481 TiB1 Kio

  1. Performances : nombre de cycles de processeur passĂ©s sur un octet gĂ©nĂ©rĂ©. Reçu sur les machines cloud N2 GCP et N2D (AMD), la commande est la mĂȘme.
  2. Qualité : niveau auquel le générateur ne réussit pas le test PractRand. S'il n'échoue pas, il y a un signe>. Si le résultat n'est pas prouvé, il y a un point d'interrogation.
  3. Corrélation des nombres de graines : Traversée PractRand avec octets alternés de huit flux avec les nombres de graines 0, 1, 2, 4, 8, 16, 32, 64. Nous utilisons PractRand avec une double convolution et des tests avancés.



Plus loin


Bien que dans notre cas il n'y ait aucun problÚme d'irréversibilité, nous pouvons toujours améliorer SHISHUA.

À mon avis, le PRNG idĂ©al a les propriĂ©tĂ©s suivantes:

  1. , 21024. 10 /. 10282 , . «» ( ). , . , 128- NEON ARM? , , .
  2. . , SHISHUA XOR . , .
  3. , 2128 ( ). SHISHUA, , . , ( ) (, , . 2).
  4. L'initialisation d'Ă©tat a une dispersion parfaite : tous les bits du nombre initial affectent tous les bits de l'Ă©tat avec la mĂȘme probabilitĂ©. Je veux en savoir plus sur SHISHUA.

L'un des problÚmes qui freinent le développement des PRNG et de la cryptographie dans son ensemble est le manque de meilleurs outils à usage général. J'ai besoin d'un outil qui puisse me donner immédiatement le résultat de mesure exact afin que je puisse comparer différentes architectures à la volée.

PractRand est génial par rapport à ce qu'il était auparavant, cependant:

  • Il ne permet pas d'Ă©valuer des gĂ©nĂ©rateurs de haute qualitĂ©, ce qui rend impossible leur comparaison les uns avec les autres. Nous devons dire: "eh bien, aprĂšs 32 tĂ©raoctets, il n'y a pas d'anomalies ..."
  • Cela prend des semaines pour l'exĂ©cuter ...

J'espÚre que la situation s'améliorera considérablement bientÎt.

All Articles