Using make, little rewrite of fort 0.51, added fort to newressu 2.4

En ole aiemmin kuvannut makefile tiedostoa, tämä on ensimmäinen. Makefile:n avulla voidaan automatisoida ohjelman käännökset kuvaamalla ne ns makefile tiedostoon. Seuraavassa makefile:ssä määritellään viisi tavoitetta: newressu, newressuw, newressum, fort ja sha256. Newressu on versio newressusta, jossa on mukana fort (sha256) ja ei ole web satunnaislukujen hakua. Newressuw on kuten edellinen, mutta mukana on myös web satunnaislukujen haku. newressum on ns vanha versio, jossa ei ole fort:ia.

Näissä tavoitteissa tarvittavat objektitiedostot on listattu objs loppuisissa listoissa kuten: newressuobjs, newressuwobjs jne…

Joissakin kohteissa tarvitaan erilaisia #define määrityksiä, ja ne on eroteltu tiedoston nimen lisäjatkeella kuten newressu.mfs.o, jossa jatke on mfs ja tarvittavat #define määritteet ovat MAIN, FORT ja SHA256.

CC =		cc
CFLAGS =	-g -Wall -Wno-pointer-sign
newressuobjs =	newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o
newressuwobjs =	newressu.mfs.o fort.w.o sha256.o intelrandom.o webrandom.o commandrandom.o
newressumobjs = newressu.m.o
sha256objs =	sha256.m.o
fortobjs =	fort.m.o sha256.o newressu.o intelrandom.o webrandom.o commandrandom.o

all:		newressu newressuw newressum sha256 fort

newressu:	$(newressuobjs)
		cc $(CFLAGS) $(newressuobjs) -o newressu -lssl

newressuw:	$(newressuwobjs)
		cc $(CFLAGS) $(newressuwobjs) -o newressuw -lssl

newressum:	$(newressumobjs)
		cc $(CFLAGS) $(newressumobjs) -o newressum

sha256:		$(sha256objs)
		cc $(CFLAGS) $(sha256objs) -o sha256

fort:		$(fortobjs)
		cc $(CFLAGS) $(fortobjs) -o fort -lssl

%.mfs.o:	%.c
		$(CC) $(CFLAGS) -DMAIN -DFORT -DSHA256 -c -o $@ $<

%.m.o:		%.c
		$(CC) $(CFLAGS) -DMAIN -c -o $@ $<

%.w.o:		%.c
		$(CC) $(CFLAGS) -DFORT_USE_WEB -c -o $@ $<

%.o:		%.c
		$(CC) $(CFLAGS) -c -o $@ $<

clean:
		rm -f *~ \#*\# *.o

Komennolla make clean all voidaan poistaa aiempi versio ja tehdä kaikki käännökset uudestaan: Ensimmäinen rm rivi on ns clean tavoitteen rivi. Seuraavat 6 riviä kääntävät newressu:n sorsia muodostaen objekteja. Seitsemäs rivi linkkaa newressun objektit ajettavaksi tiedostoksi newressu. Loput rivit tekevät saman newressuw:lle newressum:lle sha256:lle ja fort:lle.

Jos muuttelet clean tavoitteen rm komentoa, kannattaa olla huolellinen, tai jopa tehdä kopio hakemistosta tai levystä. Pieni virhe rm komennossa voi aiheuttaa koko hakemiston tai pahimmassa tapauksessa levyn tyhjentymisen.

$ make clean all
rm -f *~ \#*\# *.o
cc -g -Wall -Wno-pointer-sign -DMAIN -DFORT -DSHA256 -c -o newressu.mfs.o newressu.c
cc -g -Wall -Wno-pointer-sign -c -o fort.o fort.c
cc -g -Wall -Wno-pointer-sign -c -o sha256.o sha256.c
cc -g -Wall -Wno-pointer-sign -c -o intelrandom.o intelrandom.c
cc -g -Wall -Wno-pointer-sign -c -o webrandom.o webrandom.c
cc -g -Wall -Wno-pointer-sign -c -o commandrandom.o commandrandom.c
cc -g -Wall -Wno-pointer-sign newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o -o newressu -lssl
cc -g -Wall -Wno-pointer-sign -DFORT_USE_WEB -c -o fort.w.o fort.c
cc -g -Wall -Wno-pointer-sign newressu.mfs.o fort.w.o sha256.o intelrandom.o webrandom.o commandrandom.o -o newressuw -lssl
cc -g -Wall -Wno-pointer-sign -DMAIN -c -o newressu.m.o newressu.c
cc -g -Wall -Wno-pointer-sign newressu.m.o -o newressum
cc -g -Wall -Wno-pointer-sign -DMAIN -c -o sha256.m.o sha256.c
cc -g -Wall -Wno-pointer-sign sha256.m.o -o sha256
cc -g -Wall -Wno-pointer-sign -DMAIN -c -o fort.m.o fort.c
cc -g -Wall -Wno-pointer-sign -c -o newressu.o newressu.c
cc -g -Wall -Wno-pointer-sign fort.m.o sha256.o newressu.o intelrandom.o webrandom.o commandrandom.o -o fort -lssl

Make kääntää vain ne tiedostot, jotka tarvitsevat käännöstä. Seuraava kuva näyttää kun sha256.c tiedoston päiväykset päivitetään touch komennolla, näin se näyttää uudemmalta kuin sen kohdetiedosto sha256.o. Tällöin se käännetään ja näin muodostetaan uusi sha256.o tiedosto. Seuraavaksi tehdään tiedoston sha256.o sisältävät linkkaukset uudestaan.

$ touch sha256.c
$ make
cc -g -Wall -Wno-pointer-sign -c -o sha256.o sha256.c
cc -g -Wall -Wno-pointer-sign newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o -o newressu -lssl
cc -g -Wall -Wno-pointer-sign newressu.mfs.o fort.w.o sha256.o intelrandom.o webrandom.o commandrandom.o -o newressuw -lssl
cc -g -Wall -Wno-pointer-sign -DMAIN -c -o sha256.m.o sha256.c
cc -g -Wall -Wno-pointer-sign sha256.m.o -o sha256
cc -g -Wall -Wno-pointer-sign fort.m.o sha256.o newressu.o intelrandom.o webrandom.o commandrandom.o -o fort -lssl

Sitten fort:in varsinaisiin sorsamuutoksiin: aiemmin tapahtuman käsittelyssä oli enemmän modeja, päättelin kuitenkin että tasapainoisen tuloksen saa, jos täytetään modella 1 peräkkäisiä puskureita puskureiden alusta loppuun. Jos täytetään vain tyhjät puskurit muihin puskureihin ei kerry paljon satunnaisuutta. Jos kuitenkin haluat, voit tietenkin kopioida haluamasi moden aiemmasta postista.

void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf)
{
  while(len>1 && buf[len-1]==0)
    len--;

  HashUpdate(&fort_pools[*pool].pool, buf, len);
  fort_pools[*pool].length+=len; // (unsigned long)2097152*16384;

#ifdef DEBUG10
  if(event_id < 65536) {
    FILE *fp1;
    if((fp1=fopen(fort_events_file, "a"))!=NULL) {
      fprintf(fp1,"id=%d", event_id);
      fprintf(fp1,", source=%02d", source);
      fprintf(fp1,", pool=%02d", *pool);
      fprintf(fp1,", mode=%d", mode);
      fprintf(fp1,", len=%d", len);
      fprintf(fp1,", data=");
      for(int c=0;c<len;c++)
        fprintf(fp1,"%02x", buf[c]);
      fprintf(fp1,"\n");
      fflush(fp1);
      fclose(fp1);
      event_id++;
    }
  }
#endif

  switch(mode) {

  case 1:
    (*pool) = ((*pool)+1) % FORT_POOLS;
    break;

  case 3:
    break; // caller decides next pool

  }
}

Reseed rutiinista on poistettu fort_pools raportti: nyt fort_pools raportti tulostetaan konsolille (stdout).

void fort_reseed(int len, unsigned char *buf)
{
  HashCtx hash;

  FORT_INTERNAL_EVENTS_START(22)

  hash_init(&hash);
  hash_update(&hash, fort_key, sizeof(fort_key));
  hash_update(&hash, (unsigned char *)&cvar,
      sizeof(cvar));
  hash_update(&hash, buf, len);
  hash_final(fort_key, &hash);
  inccvar();

  memset(&hash, 0, sizeof(hash));

  if(fort_next_save != 0) {
    IUTIME seconds;
    seconds = getseconds();
    
    char timezone[10];
    strftime(timezone, sizeof(timezone), "%Z",
             localtime((time_t *)&seconds) );
    if(strcmp(current_timezone,timezone)) {
      fort_next_save=1;
      strcpy(current_timezone,timezone);
    }
    
    if(fort_next_save != 0 &&
       seconds >= fort_next_save) {
      
      IUTIME diff=
        timegm(localtime((time_t *)&seconds))-seconds;
      
      fort_next_save = seconds -
        ((seconds+diff) %
         FORT_SECONDS_BETWEEN_SAVES) +
        FORT_SECONDS_BETWEEN_SAVES;
      
      fort_save();
    }
  }

  FORT_INTERNAL_EVENTS_END(23)
}

fort_random_datasta on poistettu koodi, joka haki “vajaaseen” puskuriin lisäbittejä ressu:sta: Nyt koodi toimii siten, että uudelleenavainnus tehdään jos edellisestä avainnuksesta on kulunut 1/10 sekuntia ja ensimmäiseen puskuriin on kertynyt FORT_MIN_POOL_SIZE merkkiä.

Aliohjelmaan on myös lisätty dump_pools_data kutsu, jolla tulostetaan tämänhetkinen puskureiden tilanne stdout:tiin (jos –fortverbose on päällä). Aliohjelmaan on myös lisätty fort_mix kutsu, joka hakee satunnaisuutta verkosta tai paikallisista lähteistä.

void fort_random_data(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char buffer[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  if(fort_verbose)
    dump_pools_data(stdout,"reseed start");
    
  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();
    
    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(buffer, &fort_pools[c].pool);
      hash_update(&hash, buffer, sizeof(buffer));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        buffer, sizeof(buffer));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update(&hash, (unsigned char *)
        &cvar, sizeof(cvar));
    hash_final(buffer, &hash);
    fort_reseed(sizeof(buffer), buffer);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(buffer, 0, sizeof(buffer));
    inccvar();

    if(fort_verbose)
      dump_pools_data(stdout,"reseed end");
  }

  fort_pseudo_random_data(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

Lisätty _xor loppuiset versiot kutsuista fort_pseudo_random_data ja fort_random_data.

void fort_pseudo_random_data_xor(int len, 
    unsigned char *buf)
{
  unsigned char tmp[HashLen];
  unsigned int n, blockbytes;
#ifdef DEBUG18
  int d=0;
#endif

  FORT_INTERNAL_EVENTS_START(18)

  blockbytes = 0;

  while(len != 0) {
    FORT_INTERNAL_EVENTS_START(19)

    fort_rekey(tmp);
    n = (len<HashLen) ? len : HashLen;

#ifdef DEBUG18

    if(fort_partial_line)
      fprintf(stdout,"\n");
    fprintf(stdout,"buf(%02x): ",d++);
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]);
    fprintf(stdout,"\ntmp:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",tmp[c]);
    fprintf(stdout,"\nsum:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]^tmp[c]);
    fprintf(stdout,"\n");

#endif
    
    for(int c=0;c<n;c++)
      buf[c]^=tmp[c];

    buf += n;
    len -= n;
    blockbytes += n;

    // rekey every 1048576 bytes if data left

    if(blockbytes >= FORT_PSEUDO_LIMIT &&
        len > 0) {                                                                                                              
      fort_rekey(fort_key);
      blockbytes = 0;
    }

    FORT_INTERNAL_EVENTS_END(20)
  }

  fort_rekey(fort_key);

  // Forget last bytes

  memset(tmp, 0, sizeof(tmp));

  FORT_INTERNAL_EVENTS_END(21)
}

void fort_random_data_xor(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char buffer[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  if(fort_verbose)
    dump_pools_data(stdout,"reseed start");
        
  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();

    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(buffer, &fort_pools[c].pool);
      hash_update(&hash, buffer, sizeof(buffer));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        buffer, sizeof(buffer));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update(&hash, (unsigned char *)
        &cvar, sizeof(cvar));
    hash_final(buffer, &hash);
    fort_reseed(sizeof(buffer), buffer);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(buffer, 0, sizeof(buffer));
    inccvar();

    if(fort_verbose)
      dump_pools_data(stdout,"random_data_xor end");

  }

  fort_pseudo_random_data_xor(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

Muutettu dump_pools rutiinia siten että se tekee raportin stdout:iin:

void dump_pools_data(FILE *fp1, char *header)
{
  int c;
  unsigned char readable[10];

  if(fort_partial_line) {
    fprintf(fp1,"\n");
    fort_partial_line=0;
  }
  fprintf(fp1,"%-27s", header);
  for(c=0;c<FORT_POOLS;c++) {
    if(c>0 && c%FORT_DUMP_POOLS_WIDTH==0)
      fprintf(fp1,"\n%-27s","");
    readable_length(readable,
	    fort_pools[c].length);
    fprintf(fp1,"%*s",
	    FORT_DUMP_POOLS_FIELD_WIDTH,
	    readable);
  }
  fprintf(fp1,"\n");
}

void dump_pools(char *header)
{
  if(fort_verbose)
    dump_pools_data(stdout,header);
}

Lisätty fort_mix rutiini, joka hakee satunnaisuutta webistä tai/ja paikallisista lähteistä: Seuraavat määritykset kertovat kuinka usein satunnaisuutta päivitetään. Paikalliset haetaan tässä tunnin välein ja web satunnaisuus 12 tunnin välein. Jos satunnaisuutta haetaan web lähteistä sitä haetaan aina sen jälkeen myös paikallisista lähteistä.

Satunnaisuuden haku web:istä on melko hidasta, ja näin web haku onkin poistettu newressu perusversiosta. Jos haluat web:in satunnaisuuden mukaan käytä newressuw komentoa.

Paikallisissa komennoissa ei voi olla newressu:n –fort kytkintä, se jää rekursiivisena komentona “luuppiin”.

static IUTIME fort_next_localmix = 0;
#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
static IUTIME fort_next_webmix = 0;
#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600

void fort_mix()
{
  int webmix=0, localmix=0;
  unsigned char temp[64];

  IUTIME seconds;

  if(fort_verbose)
    dump_pools_data(stdout,"fort_mix");
  
  seconds = getseconds();
  
  webmix=0;
  localmix=0;

  if(fort_next_webmix == 0 ||
     fort_next_webmix <= seconds) {
    fort_next_webmix=seconds+FORT_SECONDS_BETWEEN_WEBMIXES;
    webmix=1;
    localmix=1;
  }

  if(fort_next_localmix == 0 ||
     fort_next_localmix <= seconds) {
    fort_next_localmix=seconds+FORT_SECONDS_BETWEEN_LOCALMIXES;
    localmix=1;
  }

  if(!webmix && !localmix)
    return;
  
  if(fort_verbose) {  
    char timebuf[128];
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&seconds));
    fprintf(stdout,"Fort mix time:      %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_webmix));
    fprintf(stdout,"Next fort webmix:   %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_localmix));
    fprintf(stdout,"Next fort localmix: %s\n",timebuf);
  }
  
  fort_internal_random_data_1(sizeof(temp), temp);
  fort_reseed(sizeof(temp), temp);
  
  dump_pools("Randomness from ressu");

#if defined FORT_USE_WEB || \
  defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED || \
  defined FORT_USE_NEWRESSU_COMMAND
  unsigned char hash[HashLen];
#endif    
  
#ifdef FORT_USE_WEB
  if(webmix) {
    char *webpages[] = {
      "https://moijari.com:5001/",
      "https://moijari.com:5005/",
      "https://moijari.com:5006/",
    };

    for(int c=0;c<sizeof(webpages)/sizeof(webpages[0]);c++) {
      unsigned char *p;
      
      unsigned char scheme[32];
      unsigned char host[32];
      unsigned char port[10];
      unsigned char rest[128];
      
      p=webpages[c];
      parse_string(scheme,sizeof(scheme),&p);
      
      if(check_string("://",p)) {
	p+=3;
	parse_string(host,sizeof(host),&p);
      } else {
	strcpy(host,scheme);
	strcpy(scheme,"http");
      }
      
      if(check_string(":",p)) {
	p++;
	parse_string(port,sizeof(port),&p);
      } else {
	strcpy(port,"80");
      }
      
      if(*p!='/') 
	strcpy(rest,"/");
      else
	strcpy(rest,p);
      
      if(fort_verbose) {    
	fprintf(stdout,"URL:%s ",webpages[c]);
	fprintf(stdout,"[scheme:%s]",scheme);
	fprintf(stdout,"[host:%s]",host);
	fprintf(stdout,"[port:%s]",port);
	fprintf(stdout,"[rest:%s]",p);
	fflush(stdout);
      }
      
      if(!strcmp(scheme,"http"))
	fort_hash_http_page(host, port, p, hash);
      else if(!strcmp(scheme,"https"))
	fort_hash_https_page(host, port, p, hash);
      
      if(fort_verbose) {
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      fort_reseed(sizeof(hash), hash);
    }
  }
#endif // #ifdef FORT_USE_WEB
    
  if(localmix) {    
#ifdef FORT_USE_URANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/urandom");
    fort_reseed(sizeof(temp), temp);
    
    dump_pools("Randomness from urandom");
#endif
  
#ifdef FORT_USE_RANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/random");
    fort_reseed(sizeof(temp), temp);
    
    dump_pools("Randomness from random");
#endif

#if defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED
    HashCtx hashctx;
#endif
    
#ifdef FORT_USE_RDRAND

    memset(temp,0,sizeof(temp));
    if(rdrand_bytes(sizeof(temp),temp)) {
      
      HashInit(&hashctx);
      HashUpdate(&hashctx, (unsigned char *) &cvar,
		 sizeof(cvar));
      HashUpdate(&hashctx, temp, sizeof(temp));
      HashFinal(hash, &hashctx);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", hash[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(hash), hash);
      inccvar();
    }  
    
#endif // #ifdef FORT_USE_RDRAND
  
#ifdef FORT_USE_RDSEED
  
    memset(temp,0,sizeof(temp));
    if(rdseed_bytes(sizeof(temp),temp)) {
      
      HashInit(&hashctx);
      HashUpdate(&hashctx, (unsigned char *) &cvar,
		 sizeof(cvar));
      HashUpdate(&hashctx, temp, sizeof(temp));
      HashFinal(hash, &hashctx);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", hash[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(hash), hash);
      inccvar();
    }

#endif // #ifdef FORT_USE_RDSEED

#ifdef FORT_USE_NEWRESSU_COMMAND

    char *commands[] = {
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --bits1024",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --bits2048",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --fast",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --single",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --urandom",
    };
    
    for(int c=0;c<sizeof(commands)/sizeof(commands[0]);c++) {
      if(strstr(commands[c], "--fort")) {
	fprintf(stderr,"%s: fort_mix(): cannot call fort recursively \"%s\"\n",
		procname,commands[c]);
      } else {
	fort_hash_command(commands[c], hash);
	fort_reseed(sizeof(hash), hash);
	dump_pools("Rand. from newressu");
      }
    }
#endif // #ifdef FORT_USE_NEWRESSU_COMMAND
  }
}

Lyhennetty fort_init() rutiinia: siirretty paikalliset ja web satunnaislukurutiinit edelliseen fort_mix() aliohjelmaan.

void fort_init()
{
  int c;
  unsigned char temp[64];
    
  if(fort_verbose) {
    fprintf(stdout,"hash: %s",
	    HashName);
    fprintf(stdout,", pools: %d*%ld", FORT_POOLS,
	    sizeof(struct fort_pool));
    fprintf(stdout,", HashCtx: %ld",
	    sizeof(HashCtx));
    fprintf(stdout,", hashsize: %d",
	    HashLen);
    fprintf(stdout,"\n");
  }
  
  unsigned int save_fort_internal_events;
  save_fort_internal_events=fort_internal_events;
  fort_internal_events=1;

  fort_next_save = 0;
  
  clearcvar();

  // first key to fort_key
  
  fort_internal_random_data_1(sizeof(fort_key), fort_key);
  dump_pools("Generate fort key w ressu");

  // Initialize buffers

  for(c=0; c<FORT_POOLS; c++) {
    fort_pools[c].length = 0;
    HashInit(&fort_pools[c].pool);
  }

  dump_pools("Initialize buffers");

#ifdef DEBUG10

  FILE *fp1;
  
  // Empty events file

  if((fp1 = fopen(fort_events_file, "w"))!=NULL)
    fclose(fp1);
  event_id = 0;

  dump_pools("Emptying events");

#endif // #ifdef DEBUG10

  // Mix fort key with web + local
  // random numbers
  
  fort_mix();

  for(c=0; c<FORT_POOLS; c++) {
    FORT_INTERNAL_EVENTS_START(31)
    fort_internal_random_data_2(sizeof(temp), temp);
    hash_update(&fort_pools[c].pool,
      temp, sizeof(temp));
    FORT_INTERNAL_EVENTS_END(32)
  }
  dump_pools("Initialize buffers 2");

#ifdef FORT_INTERNAL_EVENTS

  if(fort_internal_events) {

    // Create some internal events

    for(c=0; c<128; c++) {
      FORT_INTERNAL_EVENTS_START(34)
      fort_internal_random_data_3(sizeof(temp), temp);
      FORT_INTERNAL_EVENTS_END(35)
    }
  }
  dump_pools("Internal events");

#endif // #ifdef FORT_INTERNAL_EVENTS

  fort_reseed_count = 0;
  fort_next_reseed = 0;

  // Reseed fort_key with new events

  fort_internal_random_data_3(sizeof(temp), temp);
  fort_reseed(sizeof(temp), temp);

  dump_pools("Reseed");

  fort_restore();

  dump_pools("Restore");

  // Forget temp

  memset(temp,0,sizeof(temp));

  fort_internal_events = save_fort_internal_events;

  //fort_reseed_count = 0;
  //fort_next_reseed = 0;

  fort_next_save = 1;
}

Newressu:un fortin käyttöön liittyvät uudet rivit:

Fort kytkimen #define

#define INPUT_SINGLE 3
#define INPUT_FORT 6
#define INPUT_URANDOM 8

Fort muutokset ressu_genbyte rutiiniin:

int ressu_genbyte()
{
  static unsigned char gent[GENT_SIZE];
  static unsigned int gent_pos=0;
  unsigned char ch;

  if(input==INPUT_RESSU) { // ressu prod
    ressu_genbytes(sizeof(ch), &ch);
  } else if(input==INPUT_DEBUG) { // ressu debug
    ressu_genbytes_debug(sizeof(ch), &ch);
  } else {
    if(gent_pos==0) {
      if(input==INPUT_FAST) // ressu_fast
	ressu_genbytes_fast(sizeof(gent),gent);
      else if(input==INPUT_SINGLE) // ressu single
	ressu_genbytes_single(sizeof(gent),gent);
#ifdef FORT
      else if(input==INPUT_FORT) // ressu fort
	fort_random_data_xor(sizeof(gent),gent);
#endif
      else if(input==INPUT_URANDOM) // urandom
	readfile_xor(sizeof(gent),gent,urandomfilename);
#ifdef USE_RANDOM
      else if(input==INPUT_RANDOM) // random
	readfile_xor(sizeof(gent),gent,randomfilename);
#endif
    } // if(gent_pos==0
    ch=gent[gent_pos];
    gent_pos=(gent_pos+1)%sizeof(gent);
  }
  return(ch);
}

Muutokset newressu:n parametreihin:

      } else if(!strcmp("--single",argv[c])) {
	input=INPUT_SINGLE;

#ifdef FORT
      } else if(!strcmp("--fort",argv[c])) {
	input=INPUT_FORT;

      } else if(!strcmp("--fortverbose",argv[c])) {
	fort_verbose=!fort_verbose;

#endif
      } else if(!strcmp("--urandom",argv[c])) {
	input=INPUT_URANDOM;

Fort käyttöön tarvittavat rivit newressun sample rutiinissa:

	  else if(input==INPUT_SINGLE) // ressu single
	    ressu_genbytes_single(sizeof(buffer),buffer);
#ifdef FORT
	  else if(input==INPUT_FORT) // ressu fort
	    fort_random_data_xor(sizeof(buffer),buffer);
#endif
	  else if(input==INPUT_URANDOM) // urandom
	    readfile_xor(sizeof(buffer),buffer,urandomfilename);

Fort:in tarvitsemat muutokset help() rutiinissa:

      { "newressu --single", "use randomness from single round of ressu" },
#ifdef FORT
      { "newressu --fort", "use randomness from fort" },
#endif
      { "newressu --urandom", "use randomness from /dev/urandom" },

Fort_init():in ajo newressun main rutiinin alussa: newressussa ei yleensä lueta/kirjoiteta satunnaisuustiedostoa, mutta fort sellaisen kirjoittaa. Muutetaan tiedoston nimi newressulle sopivammaksi newressufort.rnd:ksi.

#ifdef FORT
  if(input==INPUT_FORT) {
    strcpy(fort_random_file,"newressufort.rnd");
    //fort_verbose=0;
    fort_init();
  }
#endif

Fort_save:n ajo newressu main():in lopussa:

#ifdef FORT
  if(input==INPUT_FORT) {
    fort_save();
  }
#endif

Lopuksi pikkumuutos ressun ytimeen, vaihdettu edelliset int muuttujat e ja byte char muuttujiin, koodi nopeutuu parin ändin verran.

#define RR8(byte,bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte,bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )

void ressu_genbytes_single(int size, unsigned char *buffer)
{
  int c, d;
  unsigned char e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = RL8(e,1); // rotate byte left 1 bits
      //e = RL8(e,3); // rotate byte left 3 bits
      //e = RR8(e,1); // rotate byte right 1 bits
      byte = ressu_clockbyte();
      if(prevbyte==-1)
	prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
	periods[count]++;
	clockbytes+=count;
	count=0;
	prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

Vielä satunnaisbittejä fort:illa:

$ ./newressu --fort
00000 59818670444809425543162104354361562640340355844080837840544433641
00001 86429255670425150916832717631514962701533107502652385464513081919
00002 76979793152447531086342437196445054777513582519487476941378535629
00003 40767991408879135401047593100792228272345030462623728007130573104
00004 14157104978698455671252478532622021194214885537707758473380527610
00005 57195382289148516698441240384630711158933262341475159938820939915
00006 41857440959364726778308992867020790449123381830117395560384712047
00007 65902370722617522378841616480412046354128476919104801535402728895
00008 69621109409433594842482505526285668086461153173873973262446568296
00009 38436993219274697910526589849396741791725743176705486096314555338

Tässä uuden version kaikki sorsat: ensin Makefile:

CC =		cc
CFLAGS =	-g -Wall -Wno-pointer-sign
newressuobjs =	newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o
newressuwobjs =	newressu.mfs.o fort.w.o sha256.o intelrandom.o webrandom.o commandrandom.o
newressumobjs = newressu.m.o
sha256objs =	sha256.m.o
fortobjs =	fort.m.o sha256.o newressu.o intelrandom.o webrandom.o commandrandom.o

all:		newressu newressuw newressum sha256 fort

newressu:	$(newressuobjs)
		cc $(CFLAGS) $(newressuobjs) -o newressu -lssl

newressuw:	$(newressuwobjs)
		cc $(CFLAGS) $(newressuwobjs) -o newressuw -lssl

newressum:	$(newressumobjs)
		cc $(CFLAGS) $(newressumobjs) -o newressum

sha256:		$(sha256objs)
		cc $(CFLAGS) $(sha256objs) -o sha256

fort:		$(fortobjs)
		cc $(CFLAGS) $(fortobjs) -o fort -lssl

%.mfs.o:	%.c
		$(CC) $(CFLAGS) -DMAIN -DFORT -DSHA256 -c -o $@ $<

%.m.o:		%.c
		$(CC) $(CFLAGS) -DMAIN -c -o $@ $<

%.w.o:		%.c
		$(CC) $(CFLAGS) -DFORT_USE_WEB -c -o $@ $<

%.o:		%.c
		$(CC) $(CFLAGS) -c -o $@ $<

clean:
		rm -f *~ \#*\# *.o

Sitten fort.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

#include <sys/time.h>
#include <errno.h>

#include <openssl/ssl.h>

#include "sha256.h"
#include "newressu.h"
#include "intelrandom.h"

extern unsigned char *procname;
static unsigned char *programname = "fort version 0.51 ©";
static unsigned char *copyright = "Copyright (c) 2020-2021 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";

#define FORT_INTERNAL_EVENTS 2

#define aDEBUG10 2
#define aDEBUG18 2

#define FORT_XOR_VERSION 2
#define FORT_ORIGINAL_VERSION 2

#include "fort.h"

int fort_events = 1;
int fort_verbose = 0;

#define DEBUG 2
#define FORT_MIN_POOL_SIZE 64
static unsigned int fort_internal_events = 1;
static unsigned int fort_internal_event_mode = 1;
int fort_partial_line = 0;

//#define FORT_USE_WEB 2 // in Makefile
#define FORT_USE_URANDOM 2
#define aFORT_USE_RANDOM 2
#define FORT_USE_NEWRESSU_COMMAND 2

unsigned char fort_random_file[128] = "fort.rnd";

#ifdef DEBUG10
static int event_id = 0;
static char fort_events_file[128] = "fortevents.deb";
#endif

#define FORT_64_POOLS 2

#ifdef FORT_64_POOLS
#define FORT_POOLS 64
typedef unsigned long FORT_COUNTER;
#else
#define FORT_POOLS 32
typedef unsigned int FORT_COUNTER;
#endif

void fort_mix();

unsigned char cvar[16];

void inccvar()
{
  int c = 0;

  /* 16 bytes, LSB first */
  while(++cvar[c] == 0 && c < sizeof(cvar)-1)
    c++;
}

void clearcvar()
{
  int c;

  for(c=0; c < sizeof(cvar); c++)
    cvar[c] = 0;
}

static IUTIME gettenths()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec*10 +
      (int)tv.tv_usec/100000);
}

static IUTIME getmicroseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec*1000000 +
      tv.tv_usec);
}

static IUTIME getseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec);
}

struct fort_pool {
  unsigned long length;
  HashCtx pool;
};
static struct fort_pool fort_pools[FORT_POOLS];

void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf)
{
  while(len>1 && buf[len-1]==0)
    len--;

  HashUpdate(&fort_pools[*pool].pool, buf, len);
  fort_pools[*pool].length+=len; // (unsigned long)2097152*16384;

#ifdef DEBUG10
  if(event_id < 65536) {
    FILE *fp1;
    if((fp1=fopen(fort_events_file, "a"))!=NULL) {
      fprintf(fp1,"id=%d", event_id);
      fprintf(fp1,", source=%02d", source);
      fprintf(fp1,", pool=%02d", *pool);
      fprintf(fp1,", mode=%d", mode);
      fprintf(fp1,", len=%d", len);
      fprintf(fp1,", data=");
      for(int c=0;c<len;c++)
        fprintf(fp1,"%02x", buf[c]);
      fprintf(fp1,"\n");
      fflush(fp1);
      fclose(fp1);
      event_id++;
    }
  }
#endif

  switch(mode) {

  case 1:
    (*pool) = ((*pool)+1) % FORT_POOLS;
    break;

  case 3:
    break; // caller decides next pool

  }
}

void fort_add_random_event_timer_start(IUTIME *micros)
{
  *micros = getmicroseconds();
}

void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *micros)
{
  unsigned char temp[2];
  IUTIME t;

  t = getmicroseconds()-*micros;
  temp[0] = t & 0xff;
  temp[1] = (t>>8) & 0xff;

  fort_add_random_event(pool, source, mode,
			sizeof(temp), temp);
}

void fort_add_random_event_time(int *pool, int source, int mode)
{
  int len;
  unsigned char temp[2];
  IUTIME t;
  static int prev_second=-1;

  t = getmicroseconds();
  temp[0] = t & 0xff;
  temp[1] = (t>>8) & 0xff;
  len=2;

  if(prev_second==temp[1]) {
    len--;
  } else {
    prev_second=temp[1];
  }

  fort_add_random_event(pool, source, mode,
	       len, temp);
}

void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf, int size)
{
  int n;

  while(len != 0) {
    n = (size<len)? size:len;
    fort_add_random_event(pool, source,
        mode, n, buf);
    buf += n;
    len -= n;
  }
}

void hash_init(HashCtx *hash)
{
  FORT_INTERNAL_EVENTS_START(10)

  HashInit(hash);

  FORT_INTERNAL_EVENTS_END(11)
}

void hash_update(HashCtx *hash, unsigned char *data, int len)
{
  FORT_INTERNAL_EVENTS_START(12)

  HashUpdate(hash, data, len);

  FORT_INTERNAL_EVENTS_END(13)
}

void hash_final(unsigned char digest[HashLen], HashCtx *hash)
{
  FORT_INTERNAL_EVENTS_START(14)

  HashFinal(digest, hash);

  FORT_INTERNAL_EVENTS_END(15)
}

static unsigned char fort_key[HashLen];

void fort_rekey(unsigned char *buf)
{
  HashCtx hash;

  FORT_INTERNAL_EVENTS_START(16)

  hash_init(&hash);
  hash_update(&hash, fort_key, sizeof(fort_key));
  hash_update(&hash, (unsigned char *)&cvar,
    sizeof(cvar));
  hash_final(buf, &hash);
  inccvar();

  // Forget hash

  memset(&hash, 0, sizeof(hash));

  FORT_INTERNAL_EVENTS_END(17)
}

#define FORT_PSEUDO_LIMIT 1048576

#ifdef FORT_ORIGINAL_VERSION

void fort_pseudo_random_data(int len, 
    unsigned char *buf)
{
  unsigned char tmp[HashLen];
  unsigned int n, blockbytes;
#ifdef DEBUG18
  int d=0;
#endif

  FORT_INTERNAL_EVENTS_START(18)

  blockbytes = 0;

  while(len != 0) {
    FORT_INTERNAL_EVENTS_START(19)

    fort_rekey(tmp);
    n = (len<HashLen) ? len : HashLen;

#ifdef DEBUG18
    
    fprintf(stdout,"\nbuf(%02x): ",d++);
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]);
    fprintf(stdout,"\ntmp:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",tmp[c]);
    fprintf(stdout,"\nsum:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]^tmp[c]);

#endif // #ifdef DEBUG18

    memcpy(buf, tmp, n);

    buf += n;
    len -= n;
    blockbytes += n;

    // rekey every 1048576 bytes if data left

    if(blockbytes >= FORT_PSEUDO_LIMIT &&
        len > 0) {                                                                                                              
      fort_rekey(fort_key);
      blockbytes = 0;
    }

    FORT_INTERNAL_EVENTS_END(20)
  }

  fort_rekey(fort_key);

  // Forget last bytes

  memset(tmp, 0, sizeof(tmp));

  FORT_INTERNAL_EVENTS_END(21)
}

#endif

// use 
// $ ./newressu --fort -x -w32 -s2 -l2000 --space | more
// to debug...

#ifdef FORT_XOR_VERSION

void fort_pseudo_random_data_xor(int len, 
    unsigned char *buf)
{
  unsigned char tmp[HashLen];
  unsigned int n, blockbytes;
#ifdef DEBUG18
  int d=0;
#endif

  FORT_INTERNAL_EVENTS_START(18)

  blockbytes = 0;

  while(len != 0) {
    FORT_INTERNAL_EVENTS_START(19)

    fort_rekey(tmp);
    n = (len<HashLen) ? len : HashLen;

#ifdef DEBUG18

    if(fort_partial_line)
      fprintf(stdout,"\n");
    fprintf(stdout,"buf(%02x): ",d++);
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]);
    fprintf(stdout,"\ntmp:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",tmp[c]);
    fprintf(stdout,"\nsum:     ");
    for(int c=0;c<n;c++)
      fprintf(stdout," %02x",buf[c]^tmp[c]);
    fprintf(stdout,"\n");

#endif
    
    for(int c=0;c<n;c++)
      buf[c]^=tmp[c];

    buf += n;
    len -= n;
    blockbytes += n;

    // rekey every 1048576 bytes if data left

    if(blockbytes >= FORT_PSEUDO_LIMIT &&
        len > 0) {                                                                                                              
      fort_rekey(fort_key);
      blockbytes = 0;
    }

    FORT_INTERNAL_EVENTS_END(20)
  }

  fort_rekey(fort_key);

  // Forget last bytes

  memset(tmp, 0, sizeof(tmp));

  FORT_INTERNAL_EVENTS_END(21)
}

#endif // #ifdef FORT_XOR_VERSION

// choose one of
//     60 (1 minute)
//     300 (5 minutes)
//     600 (10 minutes)
//     900 (15 minutes)
//     1200 (20 minutes)
//     1800 (30 minutes)
//     3600 (hour)
//     7200 (2 hours)
//     10800 (3 hours)
//     14400 (4 hours)
//     21600 (6 hours)
//     28800 (8 hours)
//     43200 (12 hours)
//     86400 (24 hours)
// to get readable report..

#define FORT_SECONDS_BETWEEN_SAVES 10*60
static IUTIME fort_next_save = 0;

#define TIMEFORMAT "%Z%Y%m%d%H%M%S"

void dump_pools(char *header);
void fort_save();

static char current_timezone[10];

void fort_reseed(int len, unsigned char *buf)
{
  HashCtx hash;

  FORT_INTERNAL_EVENTS_START(22)

  hash_init(&hash);
  hash_update(&hash, fort_key, sizeof(fort_key));
  hash_update(&hash, (unsigned char *)&cvar,
      sizeof(cvar));
  hash_update(&hash, buf, len);
  hash_final(fort_key, &hash);
  inccvar();

  memset(&hash, 0, sizeof(hash));

  if(fort_next_save != 0) {
    IUTIME seconds;
    seconds = getseconds();
    
    char timezone[10];
    strftime(timezone, sizeof(timezone), "%Z",
             localtime((time_t *)&seconds) );
    if(strcmp(current_timezone,timezone)) {
      fort_next_save=1;
      strcpy(current_timezone,timezone);
    }
    
    if(fort_next_save != 0 &&
       seconds >= fort_next_save) {
      
      IUTIME diff=
        timegm(localtime((time_t *)&seconds))-seconds;
      
      fort_next_save = seconds -
        ((seconds+diff) %
         FORT_SECONDS_BETWEEN_SAVES) +
        FORT_SECONDS_BETWEEN_SAVES;
      
      fort_save();
    }
  }

  FORT_INTERNAL_EVENTS_END(23)
}

void dump_pools_data(FILE *fp1, char *header);

static FORT_COUNTER fort_reseed_count = 0;
static IUTIME fort_next_reseed = 0;

#ifdef FORT_ORIGINAL_VERSION

void fort_random_data(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char buffer[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  if(fort_verbose)
    dump_pools_data(stdout,"reseed start");
    
  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();
    
    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(buffer, &fort_pools[c].pool);
      hash_update(&hash, buffer, sizeof(buffer));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        buffer, sizeof(buffer));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update(&hash, (unsigned char *)
        &cvar, sizeof(cvar));
    hash_final(buffer, &hash);
    fort_reseed(sizeof(buffer), buffer);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(buffer, 0, sizeof(buffer));
    inccvar();

    if(fort_verbose)
      dump_pools_data(stdout,"reseed end");
  }

  fort_pseudo_random_data(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

#endif // #ifdef FORT_ORIGINAL_VERSION

#ifdef FORT_XOR_VERSION

void fort_random_data_xor(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char buffer[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  if(fort_verbose)
    dump_pools_data(stdout,"reseed start");
        
  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();

    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(buffer, &fort_pools[c].pool);
      hash_update(&hash, buffer, sizeof(buffer));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        buffer, sizeof(buffer));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update(&hash, (unsigned char *)
        &cvar, sizeof(cvar));
    hash_final(buffer, &hash);
    fort_reseed(sizeof(buffer), buffer);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(buffer, 0, sizeof(buffer));
    inccvar();

    if(fort_verbose)
      dump_pools_data(stdout,"random_data_xor end");

  }

  fort_pseudo_random_data_xor(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

#endif // #ifdef FORT_XOR_VERSION

#define FORTCNT 128

static unsigned int fort_cnt = FORTCNT;
static unsigned char fort_bytes[FORTCNT];
static int fort_byte = 999999999;

int fort_random_data_byte()
{
  if(fort_byte >= fort_cnt) {
    fort_random_data(fort_cnt, fort_bytes);
    fort_byte = 0;
  }
  return(fort_bytes[fort_byte++]);
}

void fort_clear()
{
  memset(fort_bytes, 0, fort_cnt);
  fort_byte = 999999998;
}

int fort_random_data_byte_limit(int limit)
{
  int c;

  while((c = fort_random_data_byte())>=
      (256/limit)*limit);

  return(c % limit);
}

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

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

#define aFORT_DUMP_POOLS_BIN 2

#ifdef FORT_DUMP_POOLS_BIN
#define FORT_DUMP_POOLS_HIGH 1023
#define FORT_DUMP_POOLS_DIVIDER 1024
#define FORT_DUMP_POOLS_FIELD_WIDTH 6
#else
#define FORT_DUMP_POOLS_HIGH 999
#define FORT_DUMP_POOLS_DIVIDER 1000
#define FORT_DUMP_POOLS_FIELD_WIDTH 5
#endif

#define FORT_DUMP_POOLS_WIDTH 32

static void readable_length(char *buf,
    unsigned long length)
{
  int c, low;

  // B = byte
  // K = kilo   10^3   2^10
  // M = mega   10^6   2^20
  // G = giga   10^9   2^30
  // T = tera   10^12  2^40
  // P = peta   10^15  2^50
  // E = exa    10^18  2^60
  // Z = zetta  10^21  2^70
  // Y = yotta  10^24  2^80

  char units[] = "BKMGTPEZY";

  strcpy(buf,"***");
  low=0;

  for(c=0; length>=low &&
      c<sizeof(units)-1; c++) {
    if(length>=low &&
        length<=FORT_DUMP_POOLS_HIGH) {
      if(units[c]!='B')
        sprintf(buf,"%ld%c", length, units[c]);
      else
        sprintf(buf,"%ld", length);
      break;
    }
    length/=FORT_DUMP_POOLS_DIVIDER;
    low=1;
  }
}

void dump_pools_data(FILE *fp1, char *header)
{
  int c;
  unsigned char readable[10];

  if(fort_partial_line) {
    fprintf(fp1,"\n");
    fort_partial_line=0;
  }
  fprintf(fp1,"%-27s", header);
  for(c=0;c<FORT_POOLS;c++) {
    if(c>0 && c%FORT_DUMP_POOLS_WIDTH==0)
      fprintf(fp1,"\n%-27s","");
    readable_length(readable,
	    fort_pools[c].length);
    fprintf(fp1,"%*s",
	    FORT_DUMP_POOLS_FIELD_WIDTH,
	    readable);
  }
  fprintf(fp1,"\n");
}

void dump_pools(char *header)
{
  if(fort_verbose)
    dump_pools_data(stdout,header);
}

#define FORT_SAVE_SIZE 1024

void fort_save()
{
  FILE *fp1;
  unsigned char buffer[FORT_SAVE_SIZE];

  if((fp1 = fopen(fort_random_file, "w"))
      != NULL) {
    fort_pseudo_random_data(sizeof(buffer), buffer);
    fwrite(buffer, 1, sizeof(buffer), fp1);
    memset(buffer, 0, sizeof(buffer));
    fclose(fp1);
  }
}

void fort_restore()
{
  int d;
  FILE *fp1;
  unsigned char buffer[FORT_SAVE_SIZE];

  if((fp1 = fopen(fort_random_file, "rb"))
      != NULL) {
    d = fread(buffer, 1, sizeof(buffer), fp1);
    fclose(fp1);
  } else {
    fort_pseudo_random_data(sizeof(buffer), buffer);
    ressu_genbytes(sizeof(buffer), buffer);
    d = sizeof(buffer);
  }
  fort_reseed(d, buffer);
  memset(buffer, 0, sizeof(buffer));

  fort_save();
}

#if defined FORT_USE_URANDOM || \
    defined FORT_USE_RANDOM

static void fort_readfile_xor(int len,
    unsigned char *buf,
    unsigned char *filename)
{
  int c, n, n2;
  unsigned char temp[64];
  FILE *fp1;

  if((fp1 = fopen(filename, "rb"))
      != NULL) {
    while(len != 0) {
      n = (len < sizeof(temp)) ?
          len : sizeof(temp);
      n2=fread(temp, 1, n, fp1);
      for(c = 0; c < n2; c++)
        buf[c] ^= temp[c];
      len -= n2;
      buf += n2;
    }
    fclose(fp1);
  }
}

#endif

#ifdef FORT_USE_WEB

static void parse_string(unsigned char *string, int size, unsigned char **p2)
{
  int count;
  unsigned char *p, *q;

  p=*p2;
  q=string;
  count=0;

  // uppercase & lowercase letters, '.'
  // or utf-8

  while(isalnum(*p)||*p=='.'||*p>0x80) {
    if(++count<size)
      *q++=*p;
    p++;
  }
  *q='\0';
  *p2=p;
}

#endif // #ifdef FORT_USE_WEB

#ifdef FORT_USE_WEB

static int check_string(unsigned char *string, unsigned char *p)
{
  int ok;

  ok=0;
  if(!strncmp(string,p,strlen(string))) {
    ok=1;
  }

  return(ok);
}

#endif // #ifdef FORT_USE_WEB

void fort_internal_random_data_1(int size, char *buf)
{
  ressu_genbytes(size, buf);
#ifdef FORT_XOR_VERSION
  fort_pseudo_random_data_xor(size, buf);
#endif
}

void fort_internal_random_data_2(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
  fort_pseudo_random_data_xor(size, buf);
#else
  fort_pseudo_random_data(size, buf);
#endif
  ressu_genbytes(size, buf);
}

void fort_internal_random_data_3(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
  fort_random_data_xor(size, buf);
#else
  fort_random_data(size, buf);
#endif
}

static IUTIME fort_next_localmix = 0;
#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
static IUTIME fort_next_webmix = 0;
#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600

void fort_mix()
{
  int webmix=0, localmix=0;
  unsigned char temp[64];

  IUTIME seconds;

  if(fort_verbose)
    dump_pools_data(stdout,"fort_mix");
  
  seconds = getseconds();
  
  webmix=0;
  localmix=0;

  if(fort_next_webmix == 0 ||
     fort_next_webmix <= seconds) {
    fort_next_webmix=seconds+FORT_SECONDS_BETWEEN_WEBMIXES;
    webmix=1;
    localmix=1;
  }

  if(fort_next_localmix == 0 ||
     fort_next_localmix <= seconds) {
    fort_next_localmix=seconds+FORT_SECONDS_BETWEEN_LOCALMIXES;
    localmix=1;
  }

  if(!webmix && !localmix)
    return;
  
  if(fort_verbose) {  
    char timebuf[128];
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&seconds));
    fprintf(stdout,"Fort mix time:      %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_webmix));
    fprintf(stdout,"Next fort webmix:   %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_localmix));
    fprintf(stdout,"Next fort localmix: %s\n",timebuf);
  }
  
  fort_internal_random_data_1(sizeof(temp), temp);
  fort_reseed(sizeof(temp), temp);
  
  dump_pools("Randomness from ressu");

#if defined FORT_USE_WEB || \
  defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED || \
  defined FORT_USE_NEWRESSU_COMMAND
  unsigned char hash[HashLen];
#endif    
  
#ifdef FORT_USE_WEB
  if(webmix) {
    char *webpages[] = {
      "https://moijari.com:5001/",
      "https://moijari.com:5005/",
      "https://moijari.com:5006/",
    };

    for(int c=0;c<sizeof(webpages)/sizeof(webpages[0]);c++) {
      unsigned char *p;
      
      unsigned char scheme[32];
      unsigned char host[32];
      unsigned char port[10];
      unsigned char rest[128];
      
      p=webpages[c];
      parse_string(scheme,sizeof(scheme),&p);
      
      if(check_string("://",p)) {
	p+=3;
	parse_string(host,sizeof(host),&p);
      } else {
	strcpy(host,scheme);
	strcpy(scheme,"http");
      }
      
      if(check_string(":",p)) {
	p++;
	parse_string(port,sizeof(port),&p);
      } else {
	strcpy(port,"80");
      }
      
      if(*p!='/') 
	strcpy(rest,"/");
      else
	strcpy(rest,p);
      
      if(fort_verbose) {    
	fprintf(stdout,"URL:%s ",webpages[c]);
	fprintf(stdout,"[scheme:%s]",scheme);
	fprintf(stdout,"[host:%s]",host);
	fprintf(stdout,"[port:%s]",port);
	fprintf(stdout,"[rest:%s]",p);
	fflush(stdout);
      }
      
      if(!strcmp(scheme,"http"))
	fort_hash_http_page(host, port, p, hash);
      else if(!strcmp(scheme,"https"))
	fort_hash_https_page(host, port, p, hash);
      
      if(fort_verbose) {
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      fort_reseed(sizeof(hash), hash);
    }
  }
#endif // #ifdef FORT_USE_WEB
    
  if(localmix) {    
#ifdef FORT_USE_URANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/urandom");
    fort_reseed(sizeof(temp), temp);
    
    dump_pools("Randomness from urandom");
#endif
  
#ifdef FORT_USE_RANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/random");
    fort_reseed(sizeof(temp), temp);
    
    dump_pools("Randomness from random");
#endif

#if defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED
    HashCtx hashctx;
#endif
    
#ifdef FORT_USE_RDRAND

    memset(temp,0,sizeof(temp));
    if(rdrand_bytes(sizeof(temp),temp)) {
      
      HashInit(&hashctx);
      HashUpdate(&hashctx, (unsigned char *) &cvar,
		 sizeof(cvar));
      HashUpdate(&hashctx, temp, sizeof(temp));
      HashFinal(hash, &hashctx);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", hash[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(hash), hash);
      inccvar();
    }  
    
#endif // #ifdef FORT_USE_RDRAND
  
#ifdef FORT_USE_RDSEED
  
    memset(temp,0,sizeof(temp));
    if(rdseed_bytes(sizeof(temp),temp)) {
      
      HashInit(&hashctx);
      HashUpdate(&hashctx, (unsigned char *) &cvar,
		 sizeof(cvar));
      HashUpdate(&hashctx, temp, sizeof(temp));
      HashFinal(hash, &hashctx);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", hash[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(hash), hash);
      inccvar();
    }

#endif // #ifdef FORT_USE_RDSEED

#ifdef FORT_USE_NEWRESSU_COMMAND

    char *commands[] = {
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --bits1024",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --bits2048",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --fast",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --single",
      "/bin/newressu -2 -s16 -w8 -l16 --space --lineno --urandom",
    };
    
    for(int c=0;c<sizeof(commands)/sizeof(commands[0]);c++) {
      if(strstr(commands[c], "--fort")) {
	fprintf(stderr,"%s: fort_mix(): cannot call fort recursively \"%s\"\n",
		procname,commands[c]);
      } else {
	fort_hash_command(commands[c], hash);
	fort_reseed(sizeof(hash), hash);
	dump_pools("Rand. from newressu");
      }
    }
#endif // #ifdef FORT_USE_NEWRESSU_COMMAND
  }
}

void fort_init()
{
  int c;
  unsigned char temp[64];
    
  if(fort_verbose) {
    fprintf(stdout,"hash: %s",
	    HashName);
    fprintf(stdout,", pools: %d*%ld", FORT_POOLS,
	    sizeof(struct fort_pool));
    fprintf(stdout,", HashCtx: %ld",
	    sizeof(HashCtx));
    fprintf(stdout,", hashsize: %d",
	    HashLen);
    fprintf(stdout,"\n");
  }
  
  unsigned int save_fort_internal_events;
  save_fort_internal_events=fort_internal_events;
  fort_internal_events=1;

  fort_next_save = 0;
  
  clearcvar();

  // first key to fort_key
  
  fort_internal_random_data_1(sizeof(fort_key), fort_key);
  dump_pools("Generate fort key w ressu");

  // Initialize buffers

  for(c=0; c<FORT_POOLS; c++) {
    fort_pools[c].length = 0;
    HashInit(&fort_pools[c].pool);
  }

  dump_pools("Initialize buffers");

#ifdef DEBUG10

  FILE *fp1;
  
  // Empty events file

  if((fp1 = fopen(fort_events_file, "w"))!=NULL)
    fclose(fp1);
  event_id = 0;

  dump_pools("Emptying events");

#endif // #ifdef DEBUG10

  // Mix fort key with web + local
  // random numbers
  
  fort_mix();

  for(c=0; c<FORT_POOLS; c++) {
    FORT_INTERNAL_EVENTS_START(31)
    fort_internal_random_data_2(sizeof(temp), temp);
    hash_update(&fort_pools[c].pool,
      temp, sizeof(temp));
    FORT_INTERNAL_EVENTS_END(32)
  }
  dump_pools("Initialize buffers 2");

#ifdef FORT_INTERNAL_EVENTS

  if(fort_internal_events) {

    // Create some internal events

    for(c=0; c<128; c++) {
      FORT_INTERNAL_EVENTS_START(34)
      fort_internal_random_data_3(sizeof(temp), temp);
      FORT_INTERNAL_EVENTS_END(35)
    }
  }
  dump_pools("Internal events");

#endif // #ifdef FORT_INTERNAL_EVENTS

  fort_reseed_count = 0;
  fort_next_reseed = 0;

  // Reseed fort_key with new events

  fort_internal_random_data_3(sizeof(temp), temp);
  fort_reseed(sizeof(temp), temp);

  dump_pools("Reseed");

  fort_restore();

  dump_pools("Restore");

  // Forget temp

  memset(temp,0,sizeof(temp));

  fort_internal_events = save_fort_internal_events;

  //fort_reseed_count = 0;
  //fort_next_reseed = 0;

  fort_next_save = 1;
}

void fort_version()
{
  fprintf(stderr,"%s",programname); // touch these outside MAIN
  fprintf(stderr,", %s\n",copyright);
}

#define aMAIN 2
#ifdef MAIN

unsigned char *procname;

int main(int argc, char *argv[])
{
  procname=argv[0];
  fort_version();
  fort_init();
  return(0);
}

#endif // #ifdef MAIN

Fort.h:

/* Perustuu Bruce Schneierin kirjassa esittämään fortuna järjestelmään.
 * Written by Jari Kuivaniemi
 */
typedef unsigned long long IUTIME;

extern int fort_verbose;
extern int fort_partial_line;

extern unsigned char fort_random_file[128];
extern unsigned char fort_pools_file[128];
#ifdef DEBUG10
static char fort_events_file[128] = "fortevents.deb";
#endif
unsigned char cvar[16];
void inccvar();
void clearcvar();

void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf);
void fort_add_random_event_timer_start(IUTIME *micros);
void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *millis);
void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf,int size);
void fort_add_random_event_time(int *pool, int source, int mode);
void fort_rekey(unsigned char *buf);
void fort_pseudo_random_data(int len,unsigned char *buf);
void fort_pseudo_random_data_xor(int len,unsigned char *buf);
void fort_reseed(int len,unsigned char *buf);
void fort_random_data(int len,unsigned char *buf);
void fort_random_data_xor(int len,unsigned char *buf);
int fort_random_data_byte();
void fort_clear();
int fort_random_data_byte_limit(int limit);
void fort_random_data_buffer(int size, unsigned char *buffer);
void fort_save();
void fort_read_file();
void fort_mix();
void fort_init();
void hash_init(HashCtx *hash);
void hash_update(HashCtx *hash, unsigned char *data, int len);
void hash_final(unsigned char digest[HashLen], HashCtx *hash);

void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);

void fort_hash_command(unsigned char *command, unsigned char *hash);

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_START(source) \
  IUTIME micros;                           \
  static int \
    pool=0, pool2=0; \
  if(fort_internal_events) { \
    fort_add_random_event_time(&pool, \
    source, fort_internal_event_mode); \
    fort_add_random_event_timer_start(&micros); \
  }
#else
#define FORT_INTERNAL_EVENTS_START(source)
#endif

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_END(source) \
  if(fort_internal_events) \
    fort_add_random_event_timer_do(&pool2, \
      source, fort_internal_event_mode, \
      &micros);
#else
#define FORT_INTERNAL_EVENTS_END(source)
#endif

#ifdef FORT_EVENTS
#define FORT_EVENTS_START(source) \
  IUTIME micros;                           \
  static int \
    pool=0, pool2=0; \
  if(fort_events) { \
    fort_add_random_event_time(&pool, \
    source, fort_event_mode); \
    fort_add_random_event_timer_start(&micros); \
  }
#else
#define FORT_EVENTS_START(source)
#endif

#ifdef FORT_EVENTS
#define FORT_EVENTS_END(source) \
  if(fort_events) \
    fort_add_random_event_timer_do(&pool2, \
      source, fort_event_mode, \
      &micros);
#else
#define FORT_EVENTS_END(source)
#endif

Intelrandom.c

#include <stdio.h>
#include <memory.h>

#include "intelrandom.h"

#if defined FORT_USE_RDRAND ||			\
    defined FORT_USE_RDSEED

// see: https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html

void _cpuid(unsigned int leaf, unsigned int subleaf,
	    unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
{
  asm volatile("cpuid"
	       : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
	       : "a" (leaf), "c" (subleaf) );
}

int _is_cpu_vendor(unsigned char *cpuvendor)
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(0, 0, &a, &b, &c, &d);

  if(memcmp((char *)(&b), cpuvendor,4)==0 &&
     memcmp((char *)(&d), cpuvendor+4,4)==0 &&
     memcmp((char *)(&c), cpuvendor+8,4)==0)
    ok=1;

  return(ok);
}

#endif

#ifdef FORT_USE_RDRAND

int _has_rdrand()
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(1, 0, &a, &b, &c, &d);
  if((c & 0x40000000) == 0x40000000) {
    ok=1;
  }

  return(ok);
}

int _rdrand_long(unsigned long *therand)
{
  unsigned char ret;

  asm volatile("rdrand %0; setc %1"
	       : "=r" (*therand), "=qm" (ret) );

  return(int) ret;
}

int rdrand_bytes(int buflen, unsigned char *buf)
{
  int n, ret = 0;
  unsigned long l;

  if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
    if(fort_verbose)
      fprintf(stdout,"Intel rdrand");
    ret=1;
  } else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
    if(fort_verbose)
      fprintf(stdout,"AMD rdrand");
    ret=1;
  }
  
  if(ret) {
    while(buflen > 0) {
      if((ret = _rdrand_long(&l)) == 0) // 1 ok, 0 fail
	break;
      if(fort_verbose)
	fprintf(stdout," %016lx",l);
      n = (buflen < sizeof(l) ? buflen : sizeof(l));
      memcpy(buf, (unsigned char *)&l, n);
      buf+=n;
      buflen-=n;
    }
  }
  return(ret);
}

#endif // #ifdef FORT_USE_RDRAND

#ifdef FORT_USE_RDSEED

int _has_rdseed()
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(7, 0, &a, &b, &c, &d);
  if((b & 0x40000) == 0x40000) {
    ok=1;
  }

  return(ok);
}

int _rdseed_long(unsigned long *therand)
{
  unsigned char ret;

  asm volatile("rdseed %0; setc %1"
	       : "=r" (*therand), "=qm" (ret) );

  return(int) ret;
}

int rdseed_bytes(int buflen, unsigned char *buf)
{
  int n, ret = 0;
  unsigned long l;

  if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"Intel rdseed");
    ret=1;
  } else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"AMD rdseed");
    ret=1;
  }
  
  if(ret) {
    while(buflen > 0) {
      if((ret = _rdseed_long(&l)) == 0) // 1 ok, 0 fail
	break;
      if(fort_verbose)
	fprintf(stdout," %016lx",l);
      n = (buflen < sizeof(l) ? buflen : sizeof(l));
      memcpy(buf, (unsigned char *)&l, n);
      buf+=n;
      buflen-=n;
    }
  }
  return(ret);
}

#endif // #ifdef FORT_USE_RDSEED

Intelrandom.h

#define aFORT_USE_RDRAND 2
#define aFORT_USE_RDSEED 2

int rdrand_bytes(int buflen, unsigned char *buf);
int rdseed_bytes(int buflen, unsigned char *buf);

extern int intelrandom_verbose;

Webrandom.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>

#include <openssl/ssl.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "sha256.h"
#include "fort.h"

extern unsigned char *procname;
extern int fort_verbose;

#include <stdarg.h>

void dbs_printf(unsigned char **buf, size_t *buf_length, const unsigned char *format, ...)
{
  int count;
  va_list args;;
  
  va_start(args, format);
  count = vsnprintf(*buf, *buf_length, format, args) + 1;
  va_end(args);
  if(*buf_length < count) {
    *buf_length = count;
    *buf = realloc(*buf, *buf_length);
    va_start(args, format);
    count = vsnprintf(*buf, *buf_length, format, args) + 1;
    va_end(args);
  }
}

int fort_connect(unsigned char *host, unsigned char *port)
{
  struct addrinfo hints, *res, *resp;
  int s, status;
  
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  
  if((status = getaddrinfo(host, port, &hints, &res)) != 0) {
    fprintf(stderr,"\n%s: getaddrinfo", procname);
    fprintf(stderr,", status %d", status);
    fprintf(stderr,", gai_strerror(): %s", gai_strerror(status));
    fprintf(stderr,", errno %d\n", errno);
    fflush(stderr);
  }
  
  for(resp=res; resp!=NULL; resp = resp->ai_next) {
    if((s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol))<0)
      continue;
    if(connect(s, resp->ai_addr, resp->ai_addrlen) == 0)
      break;
    close(s);
  }

  freeaddrinfo(res);

  return(s);
}

void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
  int s,status,bytes,total;

  if((s = fort_connect(host, port))<0) {
    fprintf(stderr,"\n%s: cannot fort_connect()", procname);
    fprintf(stderr,", status: %d", s);
    fprintf(stderr,", errno: %d" , errno);
    perror("fort_connect");
    fflush(stderr);
  }

  unsigned char *format =
    "GET %s HTTP/1.0\r\n"
    "Host: %s\r\n";
  static unsigned char *msg = NULL;
  static size_t msg_length=0;

  dbs_printf(&msg, &msg_length, format, page, host);
  
  if((status=write(s, msg, strlen(msg)))<0) {
    fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
    perror("write");
    fflush(stderr);
  }

  HashCtx ctx;
  char buffer[1024];

  HashInit(&ctx);
  total=0;
  while((bytes = read(s, buffer, sizeof(buffer)))>0) {
    //write(1,buffer,bytes);
    HashUpdate(&ctx, buffer, bytes);
    total+=bytes;
  }

  HashFinal(hash, &ctx);

  if(fort_verbose) {
    fprintf(stdout,"fort_hash_http_page:");
    fprintf(stdout," %d bytes read", total);
    fprintf(stdout,", sha256: ");
    for(int c = 0;c < HashLen; c++) {
      fprintf(stdout,"%02x", hash[c]);
    }
  }

  close(s);
}

void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
  int s, status, bytes, total;

  SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;
  SSL *ssl;

  SSL_library_init(); //see: http://h30266.www3.hpe.com/odl/axpos/opsys/vmsos84/BA554_90007/ch04s03.html
  OpenSSL_add_ssl_algorithms();
  SSL_load_error_strings();

  if((method = (SSL_METHOD *)    
      SSLv23_client_method()) == NULL) {
    fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
    fflush(stderr);
  }

  if((ctx=SSL_CTX_new(method)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
    fflush(stderr);
  }

  if((ssl=SSL_new(ctx)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_new()", procname);
    fflush(stderr);
  }

  if((s = fort_connect(host, port))<0) {
    fprintf(stderr,"\n%s: cannot fort_connect()", procname);
    fprintf(stderr,", status: %d", s);
    fprintf(stderr,", errno: %d" , errno);
    perror("fort_connect");
    fflush(stderr);
  }

  SSL_set_fd(ssl,s);

  if((status=SSL_connect(ssl))<=0) {
    fprintf(stderr,"\n%s: cannot SSL_connect()", procname);
    fprintf(stderr,", status: %d", status);
    fprintf(stderr,", errno: %d" , errno);
    fprintf(stderr,", SSL_get_error(): %d\n", SSL_get_error(ssl,status));
    perror("SSL_connect");
    fflush(stderr);
  }

  unsigned char *format =
    "GET %s HTTP/1.0\r\n"
    "Host: %s\r\n";
  static unsigned char *msg = NULL;
  static size_t msg_length=0;

  dbs_printf(&msg, &msg_length, format, page, host);

  if((status=SSL_write(ssl, msg, strlen(msg)))<0) {
    fprintf(stderr,"\n%s: SSL_write()", procname);
    fprintf(stderr,", status: %d", status);
    fprintf(stderr,", errno: %d", errno);
    fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
    perror("SSL_write");
    fflush(stderr);
  }
  fflush(stdout);
  
  HashCtx hashctx;
  char buffer[1024];

  HashInit(&hashctx);
  total=0;
  while((bytes=SSL_read(ssl, buffer, sizeof(buffer)))>0) {
    //write(1,buffer,bytes);
    HashUpdate(&hashctx, buffer, bytes);
    total+=bytes;
  }
  fflush(stdout);
  if(bytes<0) {
    fprintf(stderr, "\n%s: SSL_read()", procname);
    fprintf(stderr, ", status: %d", status);
    fprintf(stderr, ", errno: %d", errno);
    fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
    perror("SSL_read");
    fflush(stderr);
  }

  fflush(stdout);
  
  HashFinal(hash, &hashctx);

  if(fort_verbose) {
    fprintf(stdout,"fort_hash_https_page:");
    fprintf(stdout," %d bytes read", total);
    fprintf(stdout,", sha256: ");
    for(int c = 0;c < HashLen; c++) {
      fprintf(stdout,"%02x", hash[c]);
    }
  }

  SSL_shutdown(ssl);
  SSL_free(ssl);
  SSL_CTX_free(ctx);
  close(s);
}

Commandrandom.c

#include <stdio.h>
#include <stdlib.h>

#include "sha256.h"
#include "fort.h"

void fort_hash_command(unsigned char *command, unsigned char *hash)
{
  int c,length;
  FILE *fp1;
  unsigned char buffer[1024];

  HashCtx hashctx;

  length=0;
  if((fp1=popen(command, "r"))!=NULL) {
    HashInit(&hashctx);

    HashUpdate(&hashctx, (unsigned char *)&cvar,sizeof(cvar));
    inccvar();

    if(fort_verbose) {
      fprintf(stdout,"fort_hash_command: %s",command);
      fflush(stdout);
    }
    
    while((c=fread(buffer,1,sizeof(buffer),fp1))>0) {
      //fwrite(buffer,1,c,stdout);
      HashUpdate(&hashctx, buffer, c);
      length+=c;
    }
    pclose(fp1);

    if(fort_verbose)
      fprintf(stdout,", %d bytes read",length);

    HashFinal(hash, &hashctx);

    if(fort_verbose) {
      fprintf(stdout,", sha256: ");
      for(int c = 0;c < HashLen; c++) {
	fprintf(stdout,"%02x", hash[c]);
      }
    
      fprintf(stdout,"\n");
      fflush(stdout);
    }
  }
}

sha256.c

/* Written from SHA256 documents by Jari Kuivaniemi, read "http://en.wikipedia.org/wiki/SHA-2" */
#include <stdio.h>
#include <memory.h>
#include <string.h>

#include "sha256.h"

extern unsigned char *procname;

//#ifdef MAIN // in Makefile

unsigned char *sha_name="SHA256 v1.0";

void SHA256Init(SHA256_CONTEXT *sha256)
{
  sha256->state[0] = 0x6a09e667;
  sha256->state[1] = 0xbb67ae85;
  sha256->state[2] = 0x3c6ef372;
  sha256->state[3] = 0xa54ff53a;
  sha256->state[4] = 0x510e527f;
  sha256->state[5] = 0x9b05688c;
  sha256->state[6] = 0x1f83d9ab;
  sha256->state[7] = 0x5be0cd19;
  
  sha256->count = 0;
}

IUWORD k256[64] = {
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

#define RR32(word,bits) ( ((word) >> (bits)) | ((word) << (32 - (bits))) )
#define RS32(word,bits) ( ((word) >> (bits)) )

void SHA256Transform(IUWORD state[8], IUBYTE buffer[64])
{
  int i;
  
  IUWORD w[64], s0;
  IUWORD a, b, c, d, e, f, g, h;
  IUWORD maj, t2, s1;
  IUWORD ch, t1;
  
  for(i=0;i<16;i++) {
    w[i] =
      (IUWORD)buffer[i*4+0] << 24 |
      (IUWORD)buffer[i*4+1] << 16 |
      (IUWORD)buffer[i*4+2] << 8  |
      (IUWORD)buffer[i*4+3];
  }
  
  for(i=16;i<64;i++) {
    s0 = (RR32(w[i-15],7)) ^ (RR32(w[i-15],18)) ^ (RS32(w[i-15],3));
    s1 = (RR32(w[i-2],17)) ^ (RR32(w[i-2],19)) ^ (RS32(w[i-2],10));
    w[i] = w[i-16] + s0 + w[i-7] + s1;
  }
  
  a = state[0];
  b = state[1];
  c = state[2];
  d = state[3];
  e = state[4];
  f = state[5];
  g = state[6];
  h = state[7];
  
  for(i=0;i<64;i++) {
    s0 = (RR32(a,2)) ^ (RR32(a,13)) ^ (RR32(a,22));
    maj = (a & b) ^ (a & c) ^ (b & c);
    t2 = s0 + maj;
    s1 = (RR32(e,6)) ^ (RR32(e,11)) ^ (RR32(e,25));
    ch = (e & f) ^ ((~ e) & g);
    t1 = h + s1 + ch + k256[i] + w[i];
    
    h = g;
    g = f;
    f = e;
    e = d + t1;
    d = c;
    c = b;
    b = a;
    a = t1 + t2;
  }
  
  state[0] = state[0] + a;
  state[1] = state[1] + b;
  state[2] = state[2] + c;
  state[3] = state[3] + d;
  state[4] = state[4] + e;
  state[5] = state[5] + f;
  state[6] = state[6] + g;
  state[7] = state[7] + h;
}

void SHA256Update(SHA256_CONTEXT *sha256, unsigned char *data, int len)
{
  int i,j;
  
  j = (int)sha256->count & 63;
  
  sha256->count+=len;
  
  if((j+len)>63) {
    memcpy(&sha256->buffer[j],data,64-j); /* last bytes of next block */
    
    SHA256Transform(sha256->state, sha256->buffer);
    for (i = 64 - j ; i + 63 < len; i += 64) {
      SHA256Transform(sha256->state, &data[i]);
    }
    j = 0;
  } else
    i=0;
  
  memcpy(&sha256->buffer[j],&data[i],len-i);
}

void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256)
{
  int i,j;
  unsigned char filelenght[8];
  IULONG count;
  
  count=sha256->count << 3;
  SHA256Update(sha256,"\200",1);
  
  while((sha256->count & 63) != 56)
    SHA256Update(sha256,"\0",1);
  
  filelenght[0]=(unsigned char)(count >> 56)&0xff;
  filelenght[1]=(unsigned char)(count >> 48)&0xff;
  filelenght[2]=(unsigned char)(count >> 40)&0xff;
  filelenght[3]=(unsigned char)(count >> 32)&0xff;
  filelenght[4]=(unsigned char)(count >> 24)&0xff;
  filelenght[5]=(unsigned char)(count >> 16)&0xff;
  filelenght[6]=(unsigned char)(count >> 8 )&0xff;
  filelenght[7]=(unsigned char)(count&0xff);
  
  SHA256Update(sha256,filelenght,sizeof(filelenght));
  
  for(i=0,j=0;i<8;i++) {
    digest[j++]=(unsigned char) (sha256->state[i] >> 24)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] >> 16)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] >> 8)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] )&0xff;
  }
}

#ifdef MAIN

void printhex(char *name, unsigned char *digest, int len)
{
  int c;

  fprintf(stdout,"%s=",name);
  for(c=0;c<len;c++) {
    fprintf(stdout,"%02x",digest[c]);
  }
  fflush(stdout);
}

int shahexdigit(int c)
{
  if(c>='0' && c<='9') return(c-'0');
  else if(c>='a' && c<='f') return(c-'a'+10);
  else if(c>='A' && c<='F') return(c-'A'+10);
  return(0);
}

void sha_test()
{
  int c,d,e,ok,allok;
  SHA256_CONTEXT sha256;
  unsigned char result[32],*p;
  
  fprintf(stdout,"%s",sha_name);
  fprintf(stdout,", Context size: %ld", sizeof(SHA256_CONTEXT));
  fprintf(stdout,", Hash size: 32");
  fprintf(stdout,", IUBYTE size: %ld", sizeof(IUBYTE));
  fprintf(stdout,", IUWORD size: %ld", sizeof(IUWORD));
  fprintf(stdout,", IULONG size: %ld", sizeof(IULONG));

  struct test {
    unsigned char *string;
    int count;
    unsigned char *result;
  } tests[] = {
    { "abc",1,"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",1,"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" },
    { "a",1000000,"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" },
    { "The quick brown fox jumps over the lazy dog",1,"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" },
  };

  allok=1;
  for(c=0;c<sizeof(tests)/sizeof(tests[0]);c++) {
    SHA256Init(&sha256);
    for(d=0;d<tests[c].count;d++)
      SHA256Update(&sha256,tests[c].string,strlen(tests[c].string));
    SHA256Final(result,&sha256);
    p=tests[c].result;
    d=0;
    ok=1;
    while(*p!='\0') {
      if(*p!='\0')
	e=shahexdigit(*p++);
      if(*p!='\0')
	e=e*16+shahexdigit(*p++);
      if(e!=result[d])
	ok=0;
      d++;
    }
    if(ok) {
      fprintf(stdout,"\nsha256 test ");
      fprintf(stdout,"string: %s",tests[c].string);
      fprintf(stdout,", count: %d, ",tests[c].count);
      printhex("tmp32",result,sizeof(result));
      fprintf(stdout,", result: %s",tests[c].result);
      fprintf(stdout," ok!!!!");
      fflush(stdout);
    } else {
      fprintf(stdout,"\nsha256 test ");
      fprintf(stdout,"string: %s",tests[c].string);
      fprintf(stdout,", count: %d, ",tests[c].count);
      printhex("tmp32",result,sizeof(result));
      fprintf(stdout,", result: %s",tests[c].result);
      fprintf(stdout," failed!!!!");
      fflush(stdout);
      allok=0;
    }
  }
  if(allok) {
    fprintf(stdout,", sha256 tests ok!!!!\n");
  } else {
    fprintf(stdout,", sha256 tests failed!!!!\n");
  }
  fflush(stdout);
}

int main(int argc, char *argv[])
{
  sha_test();
}

#endif

sha256.h

#ifndef SHA256_H
#define SHA256_H

#define HashName   "SHA256"
#define HashInit   SHA256Init
#define HashUpdate SHA256Update
#define HashFinal  SHA256Final
#define HashLen    32
#define HashCtx    SHA256_CONTEXT

typedef unsigned char IUBYTE;
typedef unsigned int IUWORD;
typedef unsigned long long IULONG;

typedef struct {
    IUWORD state[8];
    IULONG count;
    IUBYTE buffer[64];
} SHA256_CONTEXT;

void SHA256Init(SHA256_CONTEXT *sha256);
void SHA256Update(SHA256_CONTEXT* sha256, unsigned char *data, int len);
void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256);

void sha_test();

#endif

Newressu.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/time.h>
#include <time.h>

//#define SHA256 2 // in Makefile

#ifdef SHA256
#include "sha256.h"
#endif

//#define FORT 2 // in Makefile

#ifdef FORT
#include "fort.h"
#endif

//#define MAIN 2 // in Makefile

#include "newressu.h"
#include "intelrandom.h"

extern unsigned char *procname;
static unsigned char *programname = "Newressu version 2.4 ©";
static unsigned char *copyright = "Copyright (c) 2013-2021 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";

static unsigned long periods[1024];
static unsigned long genbytes=0;
static unsigned long clockbytes=0;

#define RESSUT_BYTES 1024
#define RESSU_BITS_NEEDED 128
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16384+1024

#define aWRITE_SAMPLE 2
#define aUSE_RANDOM 2
#define aDEBUG4 2
#define DEBUG_SORTED 2

#ifdef MAIN
static unsigned char samplefilename[128]="newressusample.rnd";
#endif
#ifdef DEBUG4
static unsigned char debugfilename[128]="newressu.deb";
#endif
static unsigned char urandomfilename[128]="/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128]="/dev/random";
#endif

static int ressu_bits_needed = RESSU_BITS_NEEDED;
static int ressut_bytes = RESSUT_BYTES;

static int stats=0;

static unsigned char ressu_clockbyte() /* JariK 2013 */
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return(tv.tv_usec & 0xff);
}

#define RR8(byte,bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte,bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )

void ressu_genbytes_single(int size, unsigned char *buffer)
{
  int c, d;
  unsigned char e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = RL8(e,1); // rotate byte left 1 bits
      //e = RL8(e,3); // rotate byte left 3 bits
      //e = RR8(e,1); // rotate byte right 1 bits
      byte = ressu_clockbyte();
      if(prevbyte==-1)
	prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
	periods[count]++;
	clockbytes+=count;
	count=0;
	prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

#ifdef OLD1

void ressu_genbytes_single(int size, unsigned char *buffer)
{
  int c, d, e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
      //e = ((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
      //e = ((e&0xfe)>>1) | ((e&0x1)<<7);  // rotate right 1
      byte = ressu_clockbyte();
      if(prevbyte==-1)
	prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
	periods[count]++;
	clockbytes+=count;
	count=0;
	prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

#endif

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

  clockbytes=0;
  for(c=0; c<RESSU_MIN_ROUNDS ||
	clockbytes < RESSU_MIN_CLOCKBYTES;c++) {
    ressu_genbytes_single(size,buffer);
  }
}

void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c, d, e, f;
  static int ressut_first=1,
    ressut_pos = 0,
    ressut_f = 0;
  static unsigned char ressut[RESSUT_BYTES];
  unsigned long prevperiods[1024];
  
  for(c=0; c<size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
	memset(ressut,0,ressut_bytes);
	ressut_first=0;
      }

      clockbytes=0;
      for(d=0;d<1024;d++) {
	periods[d]=0;
      }
      
      int rndbits=0;
      int lim, lim1=0, lim2=0;
      int lim1a, lim1b;
      int high1, high2;
      
      for(d=0; rndbits<ressu_bits_needed ||
	  d<RESSU_MIN_ROUNDS ||
	  clockbytes < RESSU_MIN_CLOCKBYTES; d++) {

	// save previous round

        for(e=0;e<1024;e++) {
	  prevperiods[e]=periods[e];
	}

	ressu_genbytes_single(ressut_bytes,ressut);

	// find new lim1
	
	lim=lim1;
	f=-1;
	for(e=0;e<1024;e++) {
	  if(prevperiods[e]>0 && prevperiods[e]==lim) {
	    if(f==-1 || (periods[e]>0 && f<periods[e])) {
	      f=periods[e];
	    }
	  }
	}

	if(f!=-1)
	  lim=f;

	lim1a=lim;
	
	// find highest amount of chains
	
	high1=-1;
	for(e=0;e<1024;e++) {
	  if(high1==-1 || high1<periods[e]) {
	    high1=periods[e];
	  }
	}

	// and second highest
	
	high2=-1;
	for(e=0;e<1024;e++) {
	  if( (high2==-1 && periods[e]<high1) ||
	      (high2<periods[e] && periods[e]<high1) ) {
	    high2=periods[e];
	  }
	}

	// and average

	int psum=0;
	int pcnt=0;
	for(e=0;e<1024;e++) {
	  if(periods[e]>0) {
	    psum+=periods[e];
	    pcnt++;
	  }
	}

	lim1b=(int)((double)psum/pcnt);
	
	// find next smaller than average

	f=-1;
	for(e=0;e<1024;e++) {
	  if( (f==-1 && periods[e]<lim1b) ||
	      (f<periods[e] && periods[e]<lim1b) ) {
	    f=periods[e];
	  }
	}

	if(f!=-1)
	  lim1b=f;

	if(lim==0 || lim>lim1b)
	  lim=lim1b;

	// if lim greater that second highest,
	// set to second highest

	if(lim>high2) {
	  lim=high2;
	}
		
	lim1=lim;

	// find next greater than lim
	
	f=-1;
	for(e=0;e<1024;e++) {
	  if(periods[e]>lim &&
	     (f==-1 || periods[e]<f))
	    f=periods[e];
	}
	if(f!=-1)
	  lim=f;

	lim2=lim;

	// calculate bits
		
	rndbits=0;
	for(e=0;e<1024;e++) {
	  if(periods[e]>0 && periods[e]<lim) {
	    rndbits+=periods[e];
	  }
	}
      } // for(d=0;
      if(stats) {
	fprintf(stdout,"rounds: %d",d);
	for(e=0;e<1024;e++) {
	  if(periods[e]>0)
	    fprintf(stdout," %d:%lu",e,periods[e]);
	}

#ifdef DEBUG_SORTED
	
	fprintf(stdout,", sorted:");
	int g=0;
	for(;;) {
	  f=-1;
	  for(e=0;e<1024;e++) {
	    if( (f==-1 && periods[e]>g) ||
		(periods[e]>g && f>periods[e]) )
	      f=periods[e];
	  }
	  if(f==-1)
	    break;

	  g=f;
	  fprintf(stdout," %d",g);
	}

#endif
	fprintf(stdout,", high1:%d",high1);
	fprintf(stdout,", high2:%d",high2);
	fprintf(stdout,", lim1a:%d",lim1a);
	fprintf(stdout,", lim1b:%d",lim1b);
	fprintf(stdout,", lim1:%d",lim1);
	fprintf(stdout,", lim2:%d",lim2);
	fprintf(stdout,", div:%f",(double)lim2/lim1);
	fprintf(stdout,", clockbytes:%ld",clockbytes);
	fprintf(stdout,", rndbits:%d",rndbits);
	fprintf(stdout,"\n");
	fflush(stdout);
      }
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

  genbytes+=size;
}

#ifdef DEBUG4
static unsigned char cc[256*1048576]; // clock_chain
static unsigned char *ccp;
static int cc_bytes;
#endif

static unsigned char ressu_clockbyte_debug() /* JariK 2013 */
{
  unsigned char c;
  struct timeval tv;
  gettimeofday(&tv, NULL);
  c=tv.tv_usec & 0xff;
#ifdef DEBUG4
  if(cc_bytes<sizeof(cc)) {
    *ccp++ = c;
    cc_bytes++;
  }
#endif
  return(c);
}

void ressu_genbytes_single_debug(int size, unsigned char *buffer)
{
  int c, d;
  unsigned char e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = RL8(e,1); // rotate byte left 1 bits
      //e = RL8(e,3); // rotate byte left 3 bits
      //e = RR8(e,1); // rotate byte right 1 bits
      byte = ressu_clockbyte_debug();
      if(prevbyte==-1)
	prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
	periods[count]++;
	clockbytes+=count;
	count=0;
	prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

void ressu_genbytes_debug(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c, d, e, f;
  static int ressut_first=1,
    ressut_pos = 0,
    ressut_f = 0;
  static unsigned char ressut[RESSUT_BYTES];
  unsigned long prevperiods[1024];
  
  for(c=0; c<size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
	memset(ressut,0,ressut_bytes);
	ressut_first=0;
      }

      clockbytes=0;
      for(d=0;d<1024;d++)
	periods[d]=0;

#ifdef DEBUG4
      ccp=cc;
      cc_bytes=0;

      while(ressu_clockbyte_debug()!=0);
      while(ressu_clockbyte_debug()==0);

      ccp=cc;
      cc_bytes=0;
#endif

      int rndbits=0;
      int lim, lim1=0, lim2=0;
      int lim1a, lim1b;
      int high1, high2;

      for(d=0; rndbits<ressu_bits_needed ||
	  d<RESSU_MIN_ROUNDS; d++) {

	// save previous round

        for(e=0;e<1024;e++) {
	  prevperiods[e]=periods[e];
	}
		
	ressu_genbytes_single_debug(ressut_bytes,ressut);

	// find new lim1
	
	lim=lim1;
	f=-1;
	for(e=0;e<1024;e++) {
	  if(prevperiods[e]>0 && prevperiods[e]==lim) {
	    if(f==-1 || (periods[e]>0 && f<periods[e])) {
	      f=periods[e];
	    }
	  }
	}

	if(f!=-1)
	  lim=f;

	lim1a=lim;
	
	// find highest amount of chains

	high1=-1;
	for(e=0;e<1024;e++) {
	  if(high1==-1 || high1<periods[e]) {
	      high1=periods[e];
	  }
	}

	// and second highest

	high2=-1;
	for(e=0;e<1024;e++) {
	  if( (high2==-1 && periods[e]<high1) ||
	      (high2<periods[e] && periods[e]<high1) ) {
	    high2=periods[e];
	  }
	}

	// and average

	int psum=0;
	int pcnt=0;
	for(e=0;e<1024;e++) {
	  if(periods[e]>0) {
	    psum+=periods[e];
	    pcnt++;
	  }
	}

	lim1b=(int)((double)psum/pcnt);
	
	// find next smaller than average

	f=-1;
	for(e=0;e<1024;e++) {
	  if( (f==-1 && periods[e]<lim1b) ||
	      (f<periods[e] && periods[e]<lim1b) ) {
	    f=periods[e];
	  }
	}

	if(f!=-1)
	  lim1b=f;

	if(lim==0 || lim>lim1b)
	  lim=lim1b;

	// if lim greater that second highest,
	// set to second highest

	if(lim>high2) {
	  lim=high2;
	}
	
	lim1=lim;

	// find next greater than lim

	f=-1;
	for(e=0;e<1024;e++) {
	  if(periods[e]>lim &&
	     (f==-1 || periods[e]<f))
	    f=periods[e];
	}
	if(f!=-1)
	  lim=f;

	lim2=lim;

	// calculate bits
	
	rndbits=0;
	for(e=0;e<1024;e++) {
	  if(periods[e]>0 && periods[e]<lim) {
	    rndbits+=periods[e];
	  }
	}
	
	if(stats) {
	  fprintf(stdout," round: %d",d);
	  for(e=0;e<1024;e++) {
	    if(periods[e]>0)
	      fprintf(stdout," %d:%lu",e,periods[e]);
	  }

#ifdef DEBUG_SORTED

	  fprintf(stdout,", sorted:");
	  int g=0;
	  for(;;) {
	    f=-1;
	    for(e=0;e<1024;e++) {
	      if( (f==-1 && periods[e]>g) ||
		  (periods[e]>g && f>periods[e]) )
		f=periods[e];
	    }
	    if(f==-1)
	      break;
	    
	    g=f;
	    fprintf(stdout," %d",g);
	  }

#endif
	  
	  fprintf(stdout," high1:%d",high1);
	  fprintf(stdout," high2:%d",high2);
	  fprintf(stdout," lim1a:%d",lim1a);
	  fprintf(stdout," lim1b:%d",lim1b);
	  fprintf(stdout," lim1:%d",lim1);
	  fprintf(stdout," lim2:%d",lim2);
	  fprintf(stdout," clockbytes:%ld",clockbytes);
	  fprintf(stdout," rndbits:%d",rndbits);
	  fprintf(stdout,"\n");
	  fflush(stdout);
	}
      } // for(d=0;
      if(stats) {
	fprintf(stdout,"rounds: %d",d);
	for(e=0;e<1024;e++) {
	  if(periods[e]>0)
	    fprintf(stdout," %d:%lu",e,periods[e]);
	}

#ifdef DEBUG_SORTED

	fprintf(stdout,", sorted:");
	int g=0;
	for(;;) {
	  f=-1;
	  for(e=0;e<1024;e++) {
	    if( (f==-1 && periods[e]>g) ||
		(periods[e]>g && f>periods[e]) )
	      f=periods[e];
	  }
	  if(f==-1)
	    break;

	  g=f;
	  fprintf(stdout," %d",g);
	}

#endif
	
	fprintf(stdout," high1:%d",high1);
	fprintf(stdout," high2:%d",high2);
	fprintf(stdout," lim1a:%d",lim1a);
	fprintf(stdout," lim1b:%d",lim1b);
	fprintf(stdout," lim1:%d",lim1);
	fprintf(stdout," lim2:%d",lim2);
	fprintf(stdout," clockbytes:%ld",clockbytes);
	fprintf(stdout," rndbits:%d",rndbits);
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
#ifdef DEBUG4
      FILE *fp1;
      if((fp1=fopen(debugfilename,"a"))!=NULL) {
	//if(lim1==-1 || lim2==-1 || lim1==lim2) {
	for(e=0;e<32;e++)
	  fprintf(fp1,"%02x",ressut[e]);

	fprintf(fp1,", ressut_bytes: %d",ressut_bytes);
	fprintf(fp1,", ressu_bits_needed: %d",ressu_bits_needed);
	fprintf(fp1,", ressu_min_rounds: %d",RESSU_MIN_ROUNDS);

	fprintf(fp1,", clockbytes: %ld",clockbytes);
	
	unsigned long total=0;	
	fprintf(fp1,", fluctuations:");
	for(e=0;e<1024;e++) {
	  if(periods[e]!=0) {
	    fprintf(fp1," %d:%lu",e,periods[e]);
	    total+=(periods[e]*e);
	  }
	}
	fprintf(fp1,", total: %lu",total);
	fprintf(fp1,", high1: %d",high1);
	fprintf(fp1,", high2: %d",high2);
	fprintf(fp1,", limit1: %d",lim1);
	fprintf(fp1,", limit2: %d",lim2);
	fprintf(fp1,", limit: %d",lim);

	fprintf(fp1,", skipped:");
	for(e=0;e<1024;e++) {
	  if(periods[e]>=lim) {
	    fprintf(fp1," %d:%lu",e,periods[e]);
	  }
	}
	
	fprintf(fp1,", counted:");
	for(e=0;e<1024;e++) {
	  if(periods[e]>0 && periods[e]<lim) {
	    fprintf(fp1," %d:%lu",e,periods[e]);
	  }
	}	
	fprintf(fp1,", rndbits: %d",rndbits);
	fprintf(fp1,", rounds: %d",d);

	int prevbyte=-1, count=0, count2=0;
	unsigned char byte, small=-1;

	fprintf(fp1,", small chains:");
	for(e=0;e<cc_bytes;e++) {
	  byte=cc[e];
	  if(prevbyte==-1) {
	    prevbyte=byte;
	    count=1;
	  }
	  if(prevbyte!=byte) {
	    if(periods[count]>=lim) {
	      if(small==1 || small==-1)
		fprintf(fp1," *");
	      small=0;
	    } else small=1;
	    if(small) {
	      fprintf(fp1," %d",count);
	      count2++;
	    }
	    count=0;
	    prevbyte=byte;
	  }
	  count++;
	}
	if(small) {
	  fprintf(fp1," %d",count);
	  count2++;
	}
	fprintf(fp1,", count: %d",count2);

	fprintf(fp1,"\n");
	fflush(fp1);
	//}
	fclose(fp1);
      } // if((fp1=fopen
#endif
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

  genbytes+=size;
}

static void readfile_xor(int len,
    unsigned char *buf,
    unsigned char *filename)
{
  int c, n, n2;
  unsigned char temp[64];
  FILE *fp1;

  if((fp1 = fopen(filename, "rb"))
      != NULL) {
    while(len != 0) {
      n = (len < sizeof(temp)) ?
          len : sizeof(temp);
      n2=fread(temp, 1, n, fp1);
      for(c = 0; c < n2; c++)
        buf[c] ^= temp[c];
      len -= n2;
      buf += n2;
    }
    fclose(fp1);
  }
}

#define INPUT_RESSU 0
#define INPUT_DEBUG 1
#define INPUT_FAST 2
#define INPUT_SINGLE 3
#define INPUT_FORT 6
#define INPUT_URANDOM 8
#define INPUT_RANDOM 9

static int input=0;

#define GENT_SIZE 1024

#define aDEBUG9 2

char *randomgen[] = { "ressu", "debug","fast","single","4","5","6","7","urandom","random" };

int ressu_genbyte()
{
  static unsigned char gent[GENT_SIZE];
  static unsigned int gent_pos=0;
  unsigned char ch;

  if(input==INPUT_RESSU) { // ressu prod
    ressu_genbytes(sizeof(ch), &ch);
  } else if(input==INPUT_DEBUG) { // ressu debug
    ressu_genbytes_debug(sizeof(ch), &ch);
  } else {
    if(gent_pos==0) {
      if(input==INPUT_FAST) // ressu_fast
	ressu_genbytes_fast(sizeof(gent),gent);
      else if(input==INPUT_SINGLE) // ressu single
	ressu_genbytes_single(sizeof(gent),gent);
#ifdef FORT
      else if(input==INPUT_FORT) // ressu fort
	fort_random_data_xor(sizeof(gent),gent);
#endif
      else if(input==INPUT_URANDOM) // urandom
	readfile_xor(sizeof(gent),gent,urandomfilename);
#ifdef USE_RANDOM
      else if(input==INPUT_RANDOM) // random
	readfile_xor(sizeof(gent),gent,randomfilename);
#endif
    } // if(gent_pos==0
    ch=gent[gent_pos];
    gent_pos=(gent_pos+1)%sizeof(gent);
  }
  return(ch);
}

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);
}

unsigned int ressu_genint()
{
  return(ressu_genshort() | ressu_genshort()<<16);
}

unsigned int ressu_genint_limit(unsigned long limit)
{
  unsigned int c;
  while((c=ressu_genint()) >= (((unsigned long)65536*65536)/limit)*limit);
  return(c%limit);
}

unsigned long ressu_genlong()
{
  return(((unsigned long)ressu_genint()) | ((unsigned long)ressu_genint())<<32);
}

unsigned long ressu_genlong_limit(unsigned long limit)
{
  unsigned long c;
  while((c=ressu_genlong()) >= (((unsigned long)0xffffffffffffffff)/limit)*limit);
  return(c%limit);
}

unsigned long ressu_gen_limit(unsigned long limit)
{
  if(limit<=256)
    return(ressu_genbyte_limit(limit));
  else if(limit<=65536)
    return(ressu_genshort_limit(limit));
  else if(limit<=(unsigned long)65536*65536)
    return(ressu_genint_limit(limit));
  else if(limit<=(unsigned long)0xffffffffffffffff)
    return(ressu_genlong_limit(limit));
  else
    return(-1);
}

void newressu_version()
{
  fprintf(stderr,"%s",programname); // touch these outside MAIN
  fprintf(stderr,", %s",copyright);
}

#ifdef MAIN

#include <stdarg.h>

#define aDEBUG31

static int stat_line_chars=0;
static int stat_line_edchars=0;

unsigned char *procname=NULL;

static void stat_line_begin()
{
#ifdef DEBUG31
  fprintf(stderr,"\n");
#else
  fprintf(stderr,"\r");
#endif  
  stat_line_edchars=stat_line_chars;
  stat_line_chars=0;
}


static void stat_line_printf(const unsigned char *format, ...)
{
  int count;
  va_list args;
  static unsigned char *stat_line_buf;
  static size_t stat_line_buf_length;

  va_start(args, format);
  count = vsnprintf(stat_line_buf, stat_line_buf_length, format, args) + 1;
  va_end(args);
  if(stat_line_buf_length < count) {
    stat_line_buf_length=count;
    stat_line_buf=realloc(stat_line_buf, stat_line_buf_length);
    va_start(args, format);
    count = vsnprintf(stat_line_buf, stat_line_buf_length, format, args) + 1;
    va_end(args);
  }
  fprintf(stderr,"%s",stat_line_buf);
  stat_line_chars+=strlen(stat_line_buf);
}

#define READABLE_NUMBER_BIN 2

#ifdef READABLE_NUMBER_BIN
#define READABLE_NUMBER_HIGH 1023
#define READABLE_NUMBER_DIVIDER 1024
#else
#define READABLE_NUMBER_HIGH 999
#define READABLE_NUMBER_DIVIDER 1000
#endif

#define READABLE_NUMBER_WIDTH 32

static void stat_line_readable(unsigned long length)
{
  int c, low;
  double length2;
  unsigned char buf10[10];
  // B = byte
  // K = kilo   10^3   2^10
  // M = mega   10^6   2^20
  // G = giga   10^9   2^30
  // T = tera   10^12  2^40
  // P = peta   10^15  2^50
  // E = exa    10^18  2^60
  // Z = zetta  10^21  2^70
  // Y = yotta  10^24  2^80
  char units[] = "BKMGTPEZY";

  strcpy(buf10,"***");
  low=0;

  for(c=0; length>=low &&
      c<sizeof(units)-1; c++) {
    if(length>=low &&
       length<=READABLE_NUMBER_HIGH) {
      if(units[c]=='B')
        sprintf(buf10,"%ld", length);
      else if(units[c]=='K')
	sprintf(buf10,"%ld%cB", length, units[c]);
      else if(length==length2)
	sprintf(buf10,"%ld%cB", length, units[c]);
      else
	sprintf(buf10,"%.1f%cB", length2, units[c]);
	
      break;
    }
    length2=(double)length/READABLE_NUMBER_DIVIDER;
    length/=READABLE_NUMBER_DIVIDER;
    low=1;
  }
  stat_line_printf("%s",buf10);
}

void stat_line_end()
{
  int c,d;

  // previous line longer than this one,
  // overwrite with spaces and backspace to
  // end
  
  if(stat_line_edchars>stat_line_chars) {
    d=stat_line_edchars-stat_line_chars;
    for(c=0;c<d;c++) {
#ifdef DEBUG31
      fprintf(stderr,"*");
#else
      fprintf(stderr," ");
#endif
    }
    for(c=0;c<d;c++)
      fprintf(stderr,"\b");
  }
  fflush(stderr);
}

int help=0;

static int utf8len(unsigned char *buf)
{
  int len;
  unsigned char *p;
  
  p=buf;
  len=0;
  while(*p!='\0') {
    if(*p<0x80 || // ascii char
       *p>0xbf) // first utf8 byte
      len++;
    p++;
  }
  return(len);
}

#define aDEBUG38 2

static void utf8getchar(int size, unsigned char *buf, int n, unsigned char *string)
{
  int d;
  unsigned char *p,*q;
  
  d=0;
  p=string;
  q=buf;

  // find first byte of character
  
  while(*p!='\0') {
    if(*p<0x80 || // ascii char
       *p>0xbf) { // first utf8 char
      if(d==n)
	break;
      d++;
    }
    p++;
  }

  // copy first byte and rest
  // of character
  
  if(*p!='\0') {
    *q++=*p; // copy first byte
    if(*p>0xbf) { // if first is utf8 char
      p++;
      for(;;) {
	if(*p>0xbf || // first utf8 char
	   *p<0x80 || // ascii char
	   *p=='\0')  // end of file
	  break;
	*q++=*p++; // copy rest of the bytes
      }
    }
  }
  *q='\0';

#ifdef DEBUG38
  fprintf(stdout,"%s: utf8getchar:",procname);
  fprintf(stdout," string: %s",string);
  fprintf(stdout,", n: %d",n);
  fprintf(stdout,", character: %s",buf);
  fprintf(stdout,"\n");
#endif
}

#define aDEBUG45

static void out_word(int size, unsigned char *buf, unsigned char *digits, unsigned long word2) // 8.5.2021 JariK
{
  int c, d, len, digitslen;
  unsigned long word;
  unsigned char string[132], character[32];

  digitslen = utf8len(digits);
  word=word2;
  len=0;
  string[0]='\0';

  if(word==0 || digitslen<2) {
    // zero
    utf8getchar(sizeof(character),character,0,digits);
    if(len+strlen(character)<sizeof(string)) {
      strcat(string,character);
      len+=strlen(character);
    }
  } else {
    // non zero
    while(word>0) {
      utf8getchar(sizeof(character),character,word%digitslen,digits);
      if(len+strlen(character)<sizeof(string)) {
	strcat(string,character);
	len+=strlen(character);
      }
      word/=digitslen;
    }
  }

  // reverse string
  
  *buf='\0';
  len=0;
  d=utf8len(string);
  for(c=d-1;c>=0;c--) {
    utf8getchar(sizeof(character),character,c,string);
    if(len+strlen(character)<size) {
      strcat(buf,character);
      len+=strlen(character);
    }
  }

#ifdef DEBUG45
  fprintf(stdout,"]\n%s: out_word: ",procname);
  fprintf(stdout," reverse string: %s",string);
  fprintf(stdout,", digits: %s",digits);
  fprintf(stdout,", int: %lu",word2);
  fprintf(stdout,"\n[");
#endif
}

#define aDEBUG58 2

static void in_word(unsigned long *word, unsigned char *digits, unsigned char *buf)
{
  int c,d,e,f,ok;
  unsigned char character[32], character2[32];

  *word=0;
  d=utf8len(buf);
  f=utf8len(digits);

  for(c=0;c<d;c++) {
    utf8getchar(sizeof(character2),character2,c,buf);
    ok=0;
    for(e=0;e<f;e++) {
      utf8getchar(sizeof(character),character,e,digits);
      if(!strcmp(character,character2)) {
	ok=1;
	break;
      }
    }
    if(ok) {
      *word=((*word)*f)+e;
    } else {
      fprintf(stdout,"%s: in_word:",procname);
      fprintf(stdout," illegal digit '%s'\n",character2);
      help=1;
    }
  }

#ifdef DEBUG58
  fprintf(stdout,"%s: in_word:",procname);
  fprintf(stdout," word: %lu",*word);
  fprintf(stdout,", digits: %s",digits);
  fprintf(stdout,", string: %s",buf);
  fprintf(stdout,"\n");
#endif
}

static void line_clear(int *len, unsigned char **buf)
{
  if(*len<1) {
    *len=129;
    *buf=realloc(*buf,*len);
  }
  **buf='\0';
}

static int line_add_string_sort(int *len, unsigned char **buf, unsigned char *string)
{
  int cmp,count,add;
  unsigned char *p;

  p=*buf;
  add=1;
  while(*p!='\0') {
    cmp=strncmp(string,p,strlen(string));
    if(cmp>0) {
      while(*p!=' ' && *p!='\0') // find next space
	p++;
      while(*p==' ' && *p!='\0') // find next non space
	p++;
    } else if(cmp==0) {
      add=0;
      break;
    } else {
      break;
    }
  }

  if(add) {
    count=strlen(*buf)+strlen(string)+1+1;
    if(*buf==NULL || count>*len) {
      int diff=p-*buf;
      *len = *len + 128;
      *buf=realloc(*buf,*len);
      p=*buf+diff;
    }
    memmove(p+strlen(string)+1,p,strlen(p)+1);
    memmove(p,string,strlen(string));
    p+=strlen(string);
    *p=' ';
  }

  return(add);
}

static void line_get_string(int len, unsigned char *buf, int n, unsigned char *string)
{
  int e,ok,count;
  unsigned char *p,*q;

  ok=0;
  p=string;
  e=0;

  while(*p!='\0') {
    if(e==n) {
      ok=1;
      break;
    }
    while(*p!=' ' && *p!='\0') // find next space
      p++;
    while(*p==' ' && *p!='\0') // find next non space
      p++;
    e++;
  }
  if(ok) {
    q=buf;
    count=0;
    while(*q!=' ' && *q!='\0') {
      if(++count<len)
	*q++=*p;
      p++;
    }
    *q='\0';
  } else {
    buf[0]='\0';
  }
}

static int size=5, zero=1, sspace=0, snewline=1,
  scrlf=1, chars=72, pchars=0, words=0, pwords=0,
  lines=10, plines=0, plinesdigits=5, slineno=1,
  quiet=0, sort=0, unique=0, sample=0;
static unsigned long limit, word;
static unsigned char *digits="0123456789", character[32];
static unsigned char digitstemp[256];
static unsigned char linenobuf[1024];

static void readword(unsigned char *buf)
{
  int d,e;
  unsigned char temp1024[1024];
  
  if(limit!=0) {
    word=0;
    
    if(zero) {
      word=ressu_gen_limit(limit); // include zeroes
      //fprintf(stdout,"(%02ld)",word);
    } else if(limit>=1) {
      while((word=ressu_gen_limit(limit))==0); // skip zeroes
    }
	  
    out_word(sizeof(temp1024),temp1024,digits,word);
	  
    // fill leading zeroes
    
    buf[0]='\0';
    utf8getchar(sizeof(character),character,0,digits);
    for(d=size-utf8len(temp1024);d>0;d--) {
      strcat(buf,character);
    }
	  
    // rest of the number
	  
    strcat(buf,temp1024);
	  
  } else if(digits!=NULL) {
    int digitslen;
	  
    buf[0]='\0';
    digitslen=utf8len(digits);
	  
    // fill whole word digit by digit
	  
    //fprintf(stdout,"[");
    for(d=0;d<size;d++) {
      if(digits[0]=='0' && !zero)
	e=ressu_gen_limit(digitslen-1)+1;
      else
	e=ressu_gen_limit(digitslen);
      utf8getchar(sizeof(temp1024),temp1024,e,digits);
      //fprintf(stdout,"%s",temp1024);
      strcat(buf,temp1024);
    }
    //fprintf(stdout,"]");
  }
}

static int line_number_length()
{
  int c;
  out_word(sizeof(linenobuf),linenobuf,"0123456789",lines-1);
  c=strlen(linenobuf);
  if(c<5)
    c=5;
  return(c);
}

static void print_line_number()
{
  unsigned char linenobuf[1024];
  
  if(pwords==0 && slineno) {
    sprintf(linenobuf,"%0*d",plinesdigits,plines);
    fprintf(stdout,"%s",linenobuf);
    fprintf(stdout," ");
  }
}

static void calc_spaces()
{
  if(sspace>=2 &&
     ( (pwords>0 && pwords%sspace==0) ||
       (slineno && pwords==0) ) )
    pchars++;
    
  if(sspace &&
     ( (pwords>0) ||
       (slineno && pwords==0) ) ) 
    pchars++;
}

static void print_spaces()
{
  if(sspace>=2 &&
     // space between word groups
     ( (pwords>0 && pwords%sspace==0) ||
     // space after linenumber
       (slineno && pwords==0) ) )
    fprintf(stdout," ");

  if(sspace &&
     // space between words
     ( (pwords>0) ||
     // space after linenumber
       (slineno && pwords==0) ) ) 
    fprintf(stdout," ");
}

static void print_word(unsigned char *buf)
{
  if(size!=0) {
    fprintf(stdout,"%*s",size,buf);
  } else {
    fprintf(stdout,"%s",buf);
  }
}

#ifdef SHA256

static void newressu_file_digest(char *filename,unsigned char *hash)
{
  int c;
  unsigned char buffer[1024];
  FILE *fp1;
  HashCtx ctx;
  
  HashInit(&ctx);
  if((fp1 = fopen(filename, "rb"))!=NULL) {
    while((c=fread(buffer, 1, sizeof(buffer), fp1)) > 0)
      HashUpdate(&ctx, buffer, c);
    fclose(fp1);
  }
  HashFinal(hash, &ctx);  
}

#endif

int main(int argc, char *argv[])
{
  int c, d, status=0;

  procname=argv[0];

  limit=0;
#ifdef DEBUG4
  ccp=cc;
  cc_bytes=0;
#endif
  clockbytes=0;
  for(d=0;d<1024;d++)
    periods[d]=0;

  // look thru command line parameters
  
  for(c=1;c<argc;c++) {
    if(!strncmp("-",argv[c],1)) {
      if(!strcmp("--lineno",argv[c])) {
	slineno=!slineno;

      } else if(!strcmp("--crlf",argv[c])) {
	scrlf=!scrlf;
	slineno=0;

      } else if(!strcmp("--quiet",argv[c])) {
	quiet=!quiet;

      } else if(!strcmp("--stats",argv[c]) ||
	!strcmp("--stat",argv[c])) {
	stats=!stats;

      } else if(!strcmp("--rand",argv[c])) {
	digits = "0123456789";
	sspace=2;
	snewline=5;
	slineno=1;
	words=10;
	chars=0;
	limit=100000;
	//size=5;
	//lines=20000;
	
      } else if(!strncmp("--space",argv[c],7)) {
	if(*(argv[c]+7)!='\0' && atoi(argv[c]+7)>1) {
	  sspace=atoi(argv[c]+7);
	} else if(c+1<argc && atoi(argv[c+1])>1) {
	  sspace=atoi(argv[c+1]);
	  c++;
	} else {
	  sspace=!sspace;
	}

      } else if(!strncmp("--newline",argv[c],9)) {
	if(*(argv[c]+9)!='\0' && atoi(argv[c]+9)>1) {
	  snewline=atoi(argv[c]+9);
	} else if(c+1<argc && atoi(argv[c+1])>1) {
	  snewline=atoi(argv[c+1]);
	  c++;
	} else {
	  snewline=!snewline;
	}

     } else if(!strcmp("--zero",argv[c])) {
	zero=!zero;

      } else if(!strcmp("--sort",argv[c])) {
	sort=!sort;
	if(sspace==0)
	  sspace=1;
		
      } else if(!strcmp("--unique",argv[c])) {
	unique=!unique;
	if(sspace==0)
	  sspace=1;
		
      } else if(!strcmp("--lotto",argv[c])) {
	sort=!sort;
	if(sspace==0)
	  sspace=1;
	//sort=1;
	//unique=1;

      } else if(!strcmp("--sample",argv[c])) {
	sample=!sample;
	
      } else if(!strcmp("--copyright",argv[c]) ||
	 !strcmp("--version",argv[c])) {
	newressu_version();
#ifdef SHA256
	unsigned char filedigest[HashLen];
	newressu_file_digest("/proc/self/exe", filedigest);
	fprintf(stderr,"\nsha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stderr,"%02x", filedigest[c]);
	}
#endif

	fprintf(stderr,"\n\n");
	help=1;
	
      } else if(!strncmp("--lim",argv[c],5)) {
	if(*(argv[c]+5)!='\0') {
	  in_word(&limit, digits, argv[c]+5);
	} else if(c+1<argc) {
	  in_word(&limit, digits, argv[c+1]);
	  c++;
	}
	if(sspace<1) // 23.6.2021
	  sspace=1;

      } else if(!strncmp("-s",argv[c],2)) {
	if(*(argv[c]+2)!='\0') {
	  size=atoi(argv[c]+2);
	} else if(c+1<argc) {
	  size=atoi(argv[c+1]);
	  c++;
	}
	limit=0; // 23.6.2021
	if(size==0)
	  size=1;
	if(size>1024)
	  size=1024;

      } else if(!strncmp("--bits",argv[c],6)) {
	if(*(argv[c]+6)!='\0') {
	  ressu_bits_needed=atoi(argv[c]+6);
	} else if(c+1<argc) {
	  ressu_bits_needed=atoi(argv[c+1]);
	  c++;
	}	

      } else if(!strncmp("--bytes",argv[c],7)) {
	if(*(argv[c]+7)!='\0') {
	  ressut_bytes=atoi(argv[c]+7);
	} else if(c+1<argc) {
	  ressut_bytes=atoi(argv[c+1]);
	  c++;
	}	

      } else if(!strncmp("-w",argv[c],2)) { // words per line
	if(*(argv[c]+2)!='\0') {
	  words=atoi(argv[c]+2);
	} else if(c+1<argc) {
	  words=atoi(argv[c+1]);
	  c++;
	}
	if(words<1)
	  words=1;
	
	chars = 0;
	
      } else if(!strncmp("-c",argv[c],2)) {  // characters per line
	if(*(argv[c]+2)!='\0') {
	  chars=atoi(argv[c]+2);
	} else if(c+1<argc) {
	  chars=atoi(argv[c+1]);
	  c++;
	}
	words=0;
	
      } else if(!strncmp("-l",argv[c],2)) { // lines
	if(*(argv[c]+2)!='\0') {
	  lines=atoi(argv[c]+2);
	} else if(c+1<argc) {
	  lines=atoi(argv[c+1]);
	  c++;
	}
	if(lines<1)
	  lines=1;

      } else if(!strcmp("-x",argv[c])) {
	digits = "0123456789abcdef";
	size=4;

      } else if(!strcmp("-d",argv[c])) {
	digits = "0123456789";
	size=5;

      } else if(!strcmp("-o",argv[c])) {
	digits = "01234567";
	size=3;

      } else if(!strcmp("-b",argv[c])) {
	digits = "01";
	size=8;

      } else if(!strcmp("-1",argv[c])) {
	digits=
	  "0123456789" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz";
	size=8;

      } else if(!strcmp("-11",argv[c])) {
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	size=8;

      } else if(!strcmp("-12",argv[c])) {
	digits=
	  "0123456789";
	size=8;

      } else if(!strcmp("-2",argv[c])) {
	digits=
	  "0123456789" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz" \
	  "_-";
	size=8;

      } else if(!strcmp("-3",argv[c])) { // 9.5.2021 JariK
	digits=
	  "!\"#$%&'()*+,-./0123456789:;<=>?@" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
	  "abcdefghijklmnopqrstuvwxyz{|}~";
	size=8;

      } else if(!strcmp("--rus",argv[c])) { // russian alphabet
	digits=
	  "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ" \
	  "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	size=8;

      } else if(!strcmp("--dnk",argv[c]) || // danish alphabet
		!strcmp("--nor",argv[c])) { // norwegian alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" \
	  "abcdefghijklmnopqrstuvwxyzæøå";
	size=8;

      } else if(!strcmp("--fin",argv[c]) || // finnish alphabet
		!strcmp("--swe",argv[c])) { // swedish alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ" \
	  "abcdefghijklmnopqrstuvwxyzåäö";
	size=8;

      } else if(!strcmp("--est",argv[c])) { // estonian alphabet

	digits=
	  "ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY" \
	  "abcdefghijklmnopqrsšzžtuvwõäöüxy";
	size=8;
  
      } else if(!strcmp("--ltu",argv[c])) { // lithuanian alphabet
	digits=
	  "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ" \
	  "aąbcčdeęėfghiįyjklmnoprsštuųūvzž";
	  
	size=8;

      } else if(!strcmp("--lva",argv[c])) { // latvian alphabet
	digits=
	  "AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ" \
	  "aābcčdeēfgģhiījkķlļmnņoprsštuūvzž";
	size=8;

      } else if(!strcmp("--fra",argv[c]) // french alphabet
		||!strcmp("--gbr",argv[c]) // great britain alphabet
		||!strcmp("--usa",argv[c]) // united states alphabet
		||!strcmp("--ita",argv[c]) // italian alphabet
		) {
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz";
	size=8;

      } else if(!strcmp("--deu",argv[c])) { // deutche alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ" \
	  "abcdefghijklmnopqrstuvwxyzäöüß";
	size=8;

      } else if(!strcmp("--grc",argv[c])) { // greek alphabet
	digits=
	  "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" \
	  "αβγδεζηθικλμνξοπρστυφχψω";
	size=8;
   
      } else if(!strcmp("--cards",argv[c])) {
	digits=
	  "🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂭🂮" \
	  "🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂽🂾" \
	  "🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃍🃎" \
	  "🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃝🃞";
	size=1;

      } else if(!strcmp("--isalnum",argv[c]) || // 9.5.2021 JariK
	        !strcmp("--isalpha",argv[c]) ||
	        !strcmp("--isdigit",argv[c]) ||
	        !strcmp("--isgraph",argv[c]) ||
	        !strcmp("--islower",argv[c]) ||
	        !strcmp("--isprint",argv[c]) ||
	        !strcmp("--ispunct",argv[c]) ||
	        !strcmp("--isupper",argv[c]) ||
		!strcmp("--isxdigit",argv[c])) {
	unsigned char *p=digitstemp;
	for(d=0;d<256;d++) {
	  if((!strcmp("--isalnum",argv[c]) && isalnum(d)) ||
	     (!strcmp("--isalpha",argv[c]) && isalpha(d)) ||
	     (!strcmp("--isdigit",argv[c]) && isdigit(d)) ||
	     (!strcmp("--isgraph",argv[c]) && isgraph(d)) ||
	     (!strcmp("--islower",argv[c]) && islower(d)) ||
	     (!strcmp("--isprint",argv[c]) && isprint(d)) ||
	     (!strcmp("--ispunct",argv[c]) && ispunct(d)) ||
	     (!strcmp("--isupper",argv[c]) && isupper(d)) ||
	     (!strcmp("--isxdigit",argv[c]) && isxdigit(d))) {
	    *p++=d;
	  }
	}
	*p='\0';
	digits=digitstemp;
	size=8;

      } else if(!strncmp("-i",argv[c],2)) {
	digits=NULL;
	if(*(argv[c]+2)!='\0') {
	  digits=argv[c]+2;
	} else if(c+1 < argc) {
	  digits=argv[c+1];
	  c++;
	}
	if(digits==NULL || utf8len(digits)<2) {
	  fprintf(stderr,"%s: not enough digits \"%s\"\n",procname,argv[c]);
	  help = 1;
	}
	size=1;

      } else if(!strcmp("--ressu",argv[c])) {
	input=INPUT_RESSU;

      } else if(!strcmp("--debug",argv[c])) {
	input=INPUT_DEBUG;

      } else if(!strcmp("--fast",argv[c])) {
	input=INPUT_FAST;

      } else if(!strcmp("--single",argv[c])) {
	input=INPUT_SINGLE;

#ifdef FORT
      } else if(!strcmp("--fort",argv[c])) {
	input=INPUT_FORT;

      } else if(!strcmp("--fortverbose",argv[c])) {
	fort_verbose=!fort_verbose;

#endif
      } else if(!strcmp("--urandom",argv[c])) {
	input=INPUT_URANDOM;

#ifdef USE_RANDOM
      } else if(!strcmp("--random",argv[c])) {
	input=INPUT_RANDOM;

#endif
      } else {
	fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
	status=1;
	help = 1;
      }
    } else {
      help = 1;

    } // if(!strncmp
  } // for(c=0

#ifdef FORT
  if(input==INPUT_FORT) {
    strcpy(fort_random_file,"newressufort.rnd");
    //fort_verbose=0;
    fort_init();
  }
#endif
  
  if(sample) {

//sample file size = CLIM*DLIM*BLKSIZE
#define CLIM 8192 // outer loop
#define DLIM 256 // inner loop
#define BLKSIZE 4096 // block size

#define STAT_LINE_READY 2
#define STAT_LINE_NOW 2
#define STAT_LINE_ANIM 2
    
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
    
    unsigned int c, d;
    unsigned char buffer[BLKSIZE];
    FILE *fp1;
    time_t secondsstart, secondsnow;
#ifdef STAT_LINE_ANIM
    long int secs, prev_secs=-1;
    int crs=0;
#endif

    if((fp1=fopen(samplefilename,"a")) != NULL) {

      secondsstart=time(NULL);

      for(c=0;c<CLIM;c++) {
	secondsnow=time(NULL);
	
	// print status line:
	// blk 10, written 10MB, 269KB/sec, left 8 h 38 m, ready at Sat 17 Jul 2021 01:57:43 EEST, now Fri 17:19:32 EEST
	
	stat_line_begin();
	stat_line_printf("\rblk %d, written ",c);
	stat_line_readable((unsigned long)c*DLIM*BLKSIZE);
	
	if(c>0) {
	  stat_line_printf(", ");
	  stat_line_readable((unsigned long)((double)c*DLIM*BLKSIZE/(secondsnow-secondsstart)) );
	  stat_line_printf("/sec");

	  char timebuf[128], timebuf2[128];
	  
#ifdef STAT_LINE_NOW

	  // print now
	  
	  stat_line_printf(", now");
	  strftime(timebuf,sizeof(timebuf),TIMEFORMAT2,
		   localtime((time_t *)&secondsnow));
	  stat_line_printf(" %s",timebuf);
#endif

	  // print left
	  
	  long int secondsleft=(int)((((double)secondsnow-secondsstart)/c)*(CLIM-c) );
	  long int secondsleft2;
	  long int temp,timeprinted=0;

	  secondsleft2=secondsleft;
	  stat_line_printf(", left");
	  
	  temp=secondsleft2/(24*3600);
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dd",temp);
	    secondsleft2-=temp*(24*3600);
	  }
	  temp=secondsleft2/3600;
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dh",temp);
	    secondsleft2-=temp*3600;
	  }
	  temp=secondsleft2/60;
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dm",temp);
	    secondsleft2-=temp*60;
	  }
	  temp=secondsleft2;
	  if(!timeprinted) {
	    stat_line_printf(" %d seconds",temp);
	  }

#ifdef STAT_LINE_READY

	  long int secondsend=(int)secondsstart+((((double)secondsnow-secondsstart)/c)*CLIM);

	  // print end date if different7
	  
	  stat_line_printf(", ready at");
	  strftime(timebuf,sizeof(timebuf),DATEFORMAT,
		   localtime((time_t *)&secondsend));
	  strftime(timebuf2,sizeof(timebuf2),DATEFORMAT,
		   localtime((time_t *)&secondsnow));
	  if(strcmp(timebuf,timebuf2)) {
	    stat_line_printf(" %s",timebuf);
	  }

	  // print end time
	  
	  strftime(timebuf,sizeof(timebuf),TIMEFORMAT,
		   localtime((time_t *)&secondsend));
	  stat_line_printf(" %s",timebuf);
#endif

	}

	stat_line_end();
	
	// do the work
	
#ifdef STAT_LINE_ANIM
	unsigned char cursor[4] = { '|', '/', '-', '\\' };

	fprintf(stderr," ");
#endif
	for(d=0;d<DLIM;d++) {
#ifdef STAT_LINE_ANIM
	  secs=time(NULL)%sizeof(cursor);
	  if(prev_secs!=secs) {
	    if(prev_secs!=-1) 
	      crs=(crs+1)%sizeof(cursor);
	    fprintf(stderr,"\b%c",cursor[crs]);
	    fflush(stderr);
	    prev_secs=secs;
	  }
#endif
	  if(input==INPUT_RESSU) // ressu prod
	    ressu_genbytes(sizeof(buffer),buffer);
	  else if(input==INPUT_DEBUG) // ressu debug
	    ressu_genbytes_debug(sizeof(buffer),buffer);
	  else if(input==INPUT_FAST) // ressu fast
	    ressu_genbytes_fast(sizeof(buffer),buffer);
	  else if(input==INPUT_SINGLE) // ressu single
	    ressu_genbytes_single(sizeof(buffer),buffer);
#ifdef FORT
	  else if(input==INPUT_FORT) // ressu fort
	    fort_random_data_xor(sizeof(buffer),buffer);
#endif
	  else if(input==INPUT_URANDOM) // urandom
	    readfile_xor(sizeof(buffer),buffer,urandomfilename);
#ifdef USE_RANDOM
	  else if(input==INPUT_RANDOM) // random
	    readfile_xor(sizeof(buffer),buffer,randomfilename);
#endif
	  
#ifdef WRITE_SAMPLE
	  fwrite(buffer,1,sizeof(buffer),fp1);
#endif
	} // for(d=0;
#ifdef STAT_LINE_ANIM
	fprintf(stderr,"\b \b");
	prev_secs=-1;
#endif
      }
      fclose(fp1);
    } // if((fp1=fopen

    // remove last status line
    
    stat_line_begin();
    stat_line_printf("Done!");
    stat_line_end();
    fprintf(stdout,"\n");
    fflush(stdout);
    exit(status);
  } // if(sample)

  // get linenumber length in digits

  plinesdigits=line_number_length();

  // get data length in digits

  if(limit!=0) {
    unsigned char wordbuf[128];
    out_word(sizeof(wordbuf),wordbuf,digits,limit-1);
    size=utf8len(wordbuf);
  }

  pchars=0;
  pwords=0;
  int linew=0;

  // in beginning of line, count printed line number
      
  if(!quiet && slineno) {
    sprintf(linenobuf,"%0*d",plinesdigits,plines);
    pchars += strlen(linenobuf);
    pchars++;
  }

  // count words
  
  while((chars>0 && pchars+size < chars) ||
	(words>0 && pwords < words)) {

    linew++;

    calc_spaces();
    
    pchars+=size;
    pwords++;
  }

  unsigned long wordvalues=1;

  for(c=0;c<size;c++) {
    if(wordvalues!=0 && wordvalues*utf8len(digits)<(unsigned long)65536*65536*65536) {
      wordvalues*=utf8len(digits);
    } else {
      wordvalues=0;
    }
  }

  if(limit > 0) {
    if(sort==1 && limit-!zero<words) {
      fprintf(stderr,"%s: limit is less than words (zero)",procname);
      fprintf(stderr,", limit:%lu",limit);
      fprintf(stderr,", words:%d",words);
      fprintf(stderr,", zero:%d",zero);
      fprintf(stderr,"\n");
      
      help=1;
      lines=0;
    }
  } else {
    if(sort==1 && size>0 && wordvalues>0 && wordvalues<linew) {
      fprintf(stderr,"%s:",procname);
      fprintf(stderr," digits is less than calculated words");
      fprintf(stderr,", digits:%d(%lu)",utf8len(digits),wordvalues);
      fprintf(stderr,", words:%d\n",linew);
      help=1;
      lines=0;
    }
  }

  // small words as single ressu_gen_limit() call
  
  if(limit==0 && wordvalues>0)
    limit=wordvalues;

  if(stats) {
    fprintf(stdout,"randomsource: %s",randomgen[input]);
    fprintf(stdout,", size: %d",size);
    fprintf(stdout,", linew: %d",linew);
    fprintf(stdout,", pchars: %d",pchars);
    fprintf(stdout,", pwords: %d",pwords);
    fprintf(stdout,", tchars: %d",size*linew*lines);
    fprintf(stdout,", digitslen: %d",utf8len(digits));
    if(wordvalues>0)
      fprintf(stdout,", wordvalues: %lu",wordvalues);
    if(limit>0)
      fprintf(stdout,", limit: %lu",limit);
    fprintf(stdout,"\n");
  }
  
  if(help) {
    struct helpline {
      char *command;
      char *text;
    } helplines[] = {
      { "newressu -d", "print random decimal digits (default)" },
      { "newressu -o", "print octal digits" },
      { "newressu -x", "print hexadecimal digits" },
      { "newressu -b", "print binary digits" },
      { "newressu -d --space", "print decimal digits, with spaces between \"words\"" },
      { "newressu -b --space", "print binary digits, with spaces between \"words\"" },
      { "newressu -d -l30", "print decimal digits, 30 lines" },
      { "newressu -d -l30 --lineno", "print decimal digits, 30 lines, no linenumbers"  },
      { "newressu -d -c128", "print decimal digits, 128 characters per line"  },
      { "newressu -d --lim10", "print decimal numbers between 0-9" },
      { "newressu -d --lim10 -x","print hexadecimal numbers with decimal limit" },
      { "newressu -d -s10 --space","print decimal numbers with spaces and wordsize 10" },
      { "newressu -d --space --zero --lim7","print rollings of dice (1-6)" },
      { "newressu -b -s1 --space","print throws of coin (0,1)" },
      { "newressu -d --lim41 -w7 --zero --lotto","print lotto numbers for finnish lotto 7x(1-40)" },
      { "newressu -d -s5 --sort -w16","print 16 sorted decimal numbers from 0 to 99999" },
      { "newressu --isalnum", "print alphanumeric characters" },
      { "newressu --isalpha", "print alphabetic characters" },
      { "newressu --isgraph", "print printables excluding space" },
      { "newressu --islower", "print lowercase characters" },
      { "newressu --ispunct", "print punctuation characters" },
      { "newressu --isupper", "print uppercase characters" },
      { "newressu -1", "print material for passwords" },
      { "newressu -iаэыуояеёюи", "print russian vowels" },
      { "newressu --ressu", "use randomness from ressu (default)" },
      { "newressu --debug", "use randomness from debugging ressu" },
      { "newressu --fast", "use randomness from fast ressu" },
      { "newressu --single", "use randomness from single round of ressu" },
#ifdef FORT
      { "newressu --fort", "use randomness from fort" },
#endif
      { "newressu --urandom", "use randomness from /dev/urandom" },
#ifdef USE_RANDOM
      { "newressu --random", "use randomness from /dev/random" },
#endif
    };
    
    for(c=0;c<sizeof(helplines)/sizeof(helplines[0]);c++) {
      fprintf(stderr,"%-50s",helplines[c].text);
      fprintf(stderr,"%-25s",helplines[c].command);
      fprintf(stderr,"\n");
    }
    for(c=0;c<chars;c++)
      fprintf(stdout,"*");
    fprintf(stdout,"\n");
    if(lines>1)
      lines=1; // print one line below help as a sample
  }

  if(lines==0)
    exit(status);

  int linecnt=0;
  unsigned char *line=NULL;
  unsigned char wordbuf[1025];
  
  for(;;) {

    if(!sort) { // also lotto

      pwords=0;

      while(pwords<linew) {
	readword(wordbuf);

	if(!quiet) {

#ifdef FORT
	  fort_partial_line = 1;
#endif
	
	  // in beginning of line, print line number

	  print_line_number();
	
	  // want to print spaces between "words"?

	  print_spaces();
	
	  // print word

	  print_word(wordbuf);
	}

	pwords++;
      } // while(pwords<linew) {
    } else { // if(!sort)

      pwords=0;
      
      line_clear(&linecnt,&line);

      // fetch and save words on this row

      while(pwords<linew) {
	readword(wordbuf);

	if(line_add_string_sort(&linecnt,&line,wordbuf)) {
	  pwords++;
	}
      } // while(pwords<linew) {

      pwords=0;

      // print words on this row

      while(pwords<linew) {

	line_get_string(sizeof(wordbuf),wordbuf,pwords,line);

	if(!quiet) {

#ifdef FORT
	  fort_partial_line = 1;
#endif	  

	  // in beginning of line, print line number

	  print_line_number();
	
	  // want to print spaces between "words"?
	
	  print_spaces();

	  // print word
	
	  print_word(wordbuf);
	}
	pwords++;
      } // while(pwords<linew) {
    } // if(!sort)

    if(!quiet) {
      fprintf(stdout,"\n");
    }
    plines++;
    if(!quiet && snewline>1 &&
       plines<lines &&
       plines%snewline==0)
      fprintf(stdout,"\n");

#ifdef FORT
    fort_partial_line = 0;
#endif
    
    // all needed lines printed?

    if(plines >= lines)
      break;

  } // for(;;)
  fflush(stdout);

#ifdef FORT
  if(input==INPUT_FORT) {
    fort_save();
  }
#endif
  exit(status);
}

#endif // MAIN

newressu.h:

void ressu_genbytes(int size, unsigned char *buffer);
Published
Categorized as ressu