Ressu kokeilu: satunnaisuuden leviämisen nopeuttaminen

Ressu kokeilu yrittää lisätä satunnaisuuden muodostamista siirtämällä kellojonon luvun jälkeen alimmasta eli “tarkimmasta” bitistä satunnaisuutta seuraavien merkkien ylempiin bitteihin. Se ei tietenkään pysty lisäämään satunnaisuutta kelloon mutta se nopeuttaa satunnaisuuden leviämistä kaikkiin puskurin bitteihin.

/*
 * Ressu−satunnaislukugeneraattori versio 1.0 (ressugen.c)
 *
 * (c)2013−2018 Jari Kuivaniemi, Kaikki oikeudet pidätetään!
 */
#include <stdio.h>
#include <sys/time.h>

unsigned char *ressu_name = "Ressu 1.0";

#ifndef OWN_CLOCK

unsigned char clockbyte() /* JariK 2013 */
{
  struct timeval tv;

  gettimeofday(&tv,NULL);

  return(tv.tv_usec & 0xff);
}

#endif

void ressu_genbytes(int size, unsigned char *buffer, int b) /* JariK 2013 */
{
  int c,d,e,f;

  f=0;
  for(c=0;c<8*b;c++) {
    for(d=0;d<size;d++) {
      e=buffer[d];
      e=((e&0x80)>>7) | ((e&0x7f)<<1);
      buffer[d]=e^clockbyte();
    }
    for(d=0;d<size;d++) {
      e=buffer[d]&1;
      buffer[(d+1)%size]^=(e<<1);
      buffer[(d+2)%size]^=(e<<2);
      buffer[(d+3)%size]^=(e<<3);
      buffer[(d+4)%size]^=(e<<4);
      buffer[(d+5)%size]^=(e<<5);
      buffer[(d+6)%size]^=(e<<6);
      buffer[(d+7)%size]^=(e<<7);
    }
    for(d=0;d<size;d++) {
      f=(f+buffer[d])%size;
      e=buffer[d];
      buffer[d]=buffer[f];
      buffer[f]=e;
    }
  }
}

Uusi kappale koodissa on tuo toinen “for(d=0;”  -kappale. For d-toistorakenne käy koko puskurin läpi ja xor:aa sarjan alimman bitin seuraavan merkin toiseksi alimpaan merkkiin, kolmannen merkin kolmenneksi alimpaan bittiin, neljännen merkin neljänneksi alimpaan bittiin jne. Tätä toistetaan kunnes ensinnäkin tämän hetkisen sarjan kahdeksan merkkiä on käsitelty ja toisaalta kunnes kaikki puskurin  alimmat bitit on käsitelty.

Seuraa kierrosrakenne, joka vaihtaa korttipakkamaisesti kaikki puskurin merkit toiseen satunnaiseen merkkiin (f). Tämän jälkeen edelliset bitit eivät enää ole vierekkäin vaan ne siirtyvät satunnaisiin kohtiin puskuria.

Jos haluat katsella bittien vaihteluha, kopioi seuraava tulostusluuppi uuden kierrosrakenteen ensimmäiseksi ja viimeiseksi.

fprintf(stdout,"\n%2d %3d",c,d);
for(g=0;g<8;g++) {
  fprintf(stdout," %02x",buffer[d+g]);
}

JK: Toinen tapa nopeuttaa satunnaisuuden siirtymistä koko puskuriin on lisätä jokaiseen merkkiin satunnaisuutta seuraavista merkeistä: Ensimmäisessä luupissa sarjan ensimmäistä merkkiä muutetaan toisen, kolmannen ja neljännen merkkien perusteella. Tässä satunnaisuus saadaan kahden merkin and:in perusteella. Ensimmäinen pari on toinen ja kolmas  merkki, toisen parin muodostavat toinen ja neljäs merkki, kolmannen parin muodostavat kolmas ja neljäs merkki.  Parin puoliskot and:ataan keskenään ja näillä kolmella merkillä xor:ataan ensimmäistä merkkiä. Tämän jälkeen voidaan ajaa taas “korttipakan sekoitus”, jolloin bitit jotka vaikuttavat toisiinsa eivät ole enää vierekkäin. Toisaalta tässähän käydään koko puskuri läpi merkki kerrallaan, joten seuraavat merkit ilman korttipaikan sekoitustakin “häviävät”.

for(d=0;d<size;d++) { // see sha2
  buffer[d%size]^=
    ((buffer[(d+1)%size]&(buffer[(d+2)%size])) ^
     (buffer[(d+1)%size]&(buffer[(d+3)%size])) ^
     (buffer[(d+2)%size]&(buffer[(d+3)%size])) );
}

Toinen versio on samanlainen mutta tässä käytetään or:ia

for(d=0;d<size;d++) {
  buffer[d%size]^=
    ((buffer[(d+1)%size]|(buffer[(d+2)%size])) ^
     (buffer[(d+1)%size]|(buffer[(d+3)%size])) ^
     (buffer[(d+2)%size]|(buffer[(d+3)%size])) );
}

Kolmannessa käytetään satunnaisbittien hakemiseen ynnäystä ja satunnaisbittien yhteenlaskussa vieläkin xor:ia.

for(d=0;d<size;d++) {
  buffer[d%size]^=
    (unsigned char)(
    (buffer[(d+1)%size]+(buffer[(d+2)%size])) ^
      (buffer[(d+1)%size]+(buffer[(d+3)%size])) ^
    (buffer[(d+2)%size]+(buffer[(d+3)%size])) );
}

Olen näköjään juuttunut tähän ressuun, toivottavasti saan aikaiseksi jotain muuta sanottavaa tertusta seuraavaan postiin.