Uusi versio Ressu:sta (v 1.7)

Tässä vielä uusi versio ressu generaattorista: uudessa versiossa ei ole enää aiempien versioiden b-muuttujaa eikä siihen liittyvää laskentaa, eli ei tarvita erillistä pääohjelmaa. Edellisessä versiossa oli useampia tapoja laskea teoreettisia bittejä, niistä on vain yksi jäljellä.

Ressufunktio muodostuu pääluupista, jonka alla on kaksi pienempää luuppia. Pääluuppi (for(c=) sanelee että kaikki puskurin bitit pitää kiertää vähintään kerran (c<8), että generaattori ei lopeta ennenkuin kaikki merkin bitit on käsitelty (c%8!=0), eli generaattorin katkokohdassa on käsitelty kaikki puskurin merkkien kahdeksan bittiä. Kellosta tulevia merkkejä pitää käsitellä vähintään 2000 kappaletta (clockbytes<2000). Lisäksi varmistetaan että teoreettisia bittejä on vähintään yksi jokaiselle generoidulle bitille (rndbits < 8*size).

Pääluupin alla on kaksi aliluuppia, joista ensimmäinen järjestelee merkin bittejä siten että ylin bitti merkissä kierretään alimmaksi ja loput bitit siirretään yhden bitin verran ylemmäksi. Lisäksi bitteihin xor:ataan yksi merkki kellosarjaa. Vuorotellen kukin bitti siirtyy alimmaiseksi ja näin kahdeksan kierroksen aikana käydään kaikki bitit läpi. Ensimmäinen aliluuppi käsittelee kaikki puskurin merkit yksi merkki kerrallaan.

Lisäksi ensimmäinen aliluuppi laskee teoreettisia satunnaisuusbittejä. Teoreettisten satunnaisbittien määrää (rndbits) lisätään yhdellä aina kun kellosarjasta tulleen merkin arvo muuttuu. Seuraavassa bittisarjassa on yksi teoreettinen bitti numeroille 46, 47, 48, 49, 4a, 4b, 4c, 4d, 4e ja 4f, eli yhteensä 10 teoreettista bittiä.

4646464646464747474747474848484848484949494949494a4a4a4a4a4a4b4b4b4b4b4b4b4c4c4c4c4c4d4d4d4d4d4d4e4e4e4e4e4f4f4f4f4f4f

Satunnaisuus edellisessä kellojonossa tulee siitä että eri merkkien lukumäärä vaihtelee, seuraavassa kunkin merkin määrä kellojonossa: F muuttuja tekee sen, että jos yksikin f:ään lisättävä merkki muuttuu kaikki loppumerkit muuttuvat erilaisiksi. Voi muuten väittää että seuraavan taulukon kuutosriveissä ei ole kovin paljon satunnaista, että satunnaisuus tulee pääasiassa 7 ja 5 pituuksisista riveistä, eli poikkeuksista sääntöön.

464646464646    6
474747474747    6
484848484848    6
494949494949    6
4a4a4a4a4a4a    6
4b4b4b4b4b4b4b  7
4c4c4c4c4c      5
4d4d4d4d4d4d    6
4e4e4e4e4e      5
4f4f4f4f4f4f    6

Toinen aliluuppi käy myös kaikki merkit läpi ja vaihtaa jokaisen merkin (muuttuja d) satunnaisen puskurin merkin kanssa (muuttuja f).

Tässä varsinainen koodi pääfunktiolle.

void ressu_genbytes(int size,
        unsigned char *buffer) /* JariK 2020 v1.7 */
{
  int c, d, e, f,
    byte, prevbyte,
    clockbytes = 0, rndbits = 0;

  prevbyte = clockbyte();
  f = 0;

  for(c=0; c < 8 || c%8 != 0 ||
      clockbytes < 2000 ||
      rndbits < 8*size; c++) {
    for(d=0; d < size; d++) {
      e = buffer[d];
      e = ((e & 0x80) >> 7) |
          ((e & 0x7f) << 1);
      byte = clockbyte();
      buffer[d] = e ^ byte;
      if(prevbyte != byte) {
        prevbyte = byte;
        rndbits++;
      }
      clockbytes++;
    }
    for(d=0; d < size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

Tässä vielä käytetty kellonluku:

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

  gettimeofday(&tv,NULL);

  return(tv.tv_usec & 0xff);
}

Seuraavassa ohjelman apufunktiot.

#define RESSUCNT 128
#define RESSU_CLEAR 2

unsigned char ressu_bytes[RESSUCNT];
int ressu_byte = 999999999;
int ressu_cnt = RESSUCNT;

void ressu_init()
{
}

int ressu_genbyte()
{
  if(ressu_byte>=ressu_cnt) {
#ifdef RESSU_CLEAR
    memset(ressu_bytes,0,ressu_cnt);
#else
    if(ressu_byte == 999999999)
      memset(ressu_bytes, 0, ressu_cnt);
#endif
    ressu_genbytes(ressu_cnt,
        ressu_bytes);
    ressu_byte=0;
  }
  return(ressu_bytes[ressu_byte++]);
}

void ressu_clear()
{
    memset(ressu_bytes, 0, ressu_cnt);
    ressu_byte = 999999998;
}

int ressu_genbyte_limit(int limit)
{
  int c;

  while((c = ressu_genbyte())>
      (256 / limit) * limit);
  return(c % limit);
}

int ressu_genshort()
{
  return(ressu_genbyte()|
         ressu_genbyte() << 8);
}

int ressu_genshort_limit(int limit)
{
  int c;

  while((c = ressu_genshort())>
      (65536 / limit) * limit);
  return(c % limit);
}

int ressu_gen32bits()
{
  return(ressu_genbyte()|
         ressu_genbyte() << 8|
         ressu_genbyte() << 16|
         ressu_genbyte() << 24);
}

void ressu_genbuffer(int size, unsigned char *buffer)
{
  int c;

  for(c = 0; c < size; c++)
    buffer[c] ^= ressu_genbyte();
}

Leave a Reply