Kaikki oikeudet pidätetään ©. Maailman parhaat satunnaisbitit: https://moijari.com:5006.
Versionumeron kasvatuksen yhteydessä käyn läpi kaikki uudet ja vanhat pääfunktiot.
Edit: korjailen raporttia vielä seuraavien viikkojen aikana
Edit: olen jatkanut ressun tutkimista ja lisäilen illan mittaan uusia kappaleita raporttiin. Lisätty kaksi uutta tilastoohjelmaa, uudelleenkirjoituskappaleet stat_line funktioista ja sample() rutiinista. Toinen tilastoohjelma sisältää tertun ytimelle toivottavasti sopivan kenttien ja tietueiden hallinnan pohjan.
Edit Lisätty loppuun kappaleita exfat bugin korjaamisesta. Bugi korjautui osittain lisäämällä tulostettavaan tiedostoon fflush ja sync.
Edit: vähennetty stat_line:n “nykimistä”. Numerokentät (readable) ovat nyt useimmiten neljän pituisia.
Edit: Lisää exfat ongelman tutkimista. Lisätty ohjelma newressutest12, joka kirjoittaa kiinteän pituisia tietueita ja lukee ja tarkistaa tietueet. (vrt newressutest10)
Edit: Muutettu komentoriviparametrejä samankaltaisiksi. Ennen parametrit olivat esimerkiksi -b, –bytes, –lines, ne olivat erilaisia joka ohjelmassa. Nyt ne on samanlaisia eli –filesize 1g, –binsize 10, –linesize 21, –lines 1m, –blocksize 1024, –blocks 1m jne. Muutenkin näiden parametrien laskentaa ja tarkistusta on järkeistetty. Huomaa, että raportin komentoesimerkeissä vanhat versiot eivät enää toimi. Myös ,/newressu –sample –filesize 1g ja muut koko-parametrit toimivat.
Edit: Lisätty stream_open -funktion avaimen muodostukseen stream_keyn lisäksi cvar. Tämä tekee uudesta stream_key:stä satunnaisemman. Näin samoja stream_key avaimia ei kierretä uudelleen ja uudelleen. Jos jostain syystä päädymme samaan stream_key:in toistamiseen, seuraavan avaimen laskemiseen käytetään erilaista cvar kenttää, jolloin saman sarjan läpikäyminen loppuu heti.
Ensimmäiset funktiot sisältävät varsinaisen kellon luvun ja kellon esikäsittelyn. Esikäsittely on uusi ominaisuus, jossa kellojono jaetaan satunnaisesti 2-257 merkkiä sisältäviin “blokkeihin”, ja joka toinen blokki palautetaan sellaisenaan (copy) ja joka toinen palautetaan käännetyssä järjestyksessä (reverse). Tällä tavalla sain kellojonon aiemman esikäsittelyn “symmetrisemmäksi”, ja koska kellojonon käsittelyssä ei enää ole aiemman version ohituksia (skip) myös kellojonon “tuhlaus” loppuu. Tämän esikäsittelyn pitäisi tehdä mahdottomaksi kellojonon arvaaminen.
Kellojonon käsittelyyn on myös lisätty uusi –fixedclock toiminto, jolla kellojonon ketjut ovat aina yhtä pitkiä. Tällä voidaan ensinnäkin miettiä muodostaako pelkkä copy-reverse ilman kellojonon vaihtelua tarvittavasti satunnaisuutta sellaisenaan, ja toisaalta taas sen ymmärtäminen, miten uusi copy-reverse vaikuttaa.
Ensiksi alkuperäinen kellojonon luku.
static unsigned char ressu_clockbyte2() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
Sitten ns kiinteämittaista kellojonoa tarjoava rutiini:
#define FIXEDCLOCKCHAINLENGTH 80
unsigned int fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
static unsigned char ressu_fixedclockbyte2() /* JariK 2022 */
{
static unsigned int clockbyte = 0, counter = 0;
if(counter == 0) {
clockbyte++;
counter += fixedclockchainlength;
}
counter--;
return(clockbyte & 0xff);
}
Tässä fixed/normal valinnan tekevä rutiini. Ensimmäisen kerran näissä raporteissa osoite funktioon (pointer to function) tyyppinen muuttuja:
unsigned char (*clockfunc)()= &ressu_clockbyte2; // normal
void ressu_setclock(int clockmode)
{
if(!clockmode)
clockfunc = &ressu_clockbyte2; // normal
else
clockfunc = &ressu_fixedclockbyte2; // fixed
}
Seuraavana “mukamas” satunnaisia lukuja tekevä rutiini. Tulos on kuitenkin satunnainen, koska sitä käytetään indeksinä satunnaislukupuskuriin. Tämä funktio oli jo copy-skip versiossa, tässä se on ulkoistettu koska sitä käytetään kaksi kertaa, kerran copy:lle ja kerran reverse:lle.
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
rando = rando +
clockbytes +
genbytes +
time(NULL) +
clock() +
get_useconds() +
ch * ch;
return(rando);
}
Tässä kellojonon esikäsittely joka kopioi tai kääntää seuraavan lohkon: (huomaa ch = (*clockfunc)() joka palauttaa joko tavallisen tai kiinteänmittaisen kellojonon).
unsigned char *ressuct; // ressu random buffer lookup
unsigned int ressuct_bytes;
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[256];
static unsigned int count = 0;
if(reverse) {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"rev: %03x ", count);
#endif
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)();
//reversebytes[c] = ressu_clockbyte2();
#ifdef DEBUG2A
fprintf(stdout," %02x", reversebytes[c]);
newressu_output = 1;
#endif
}
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
ch = reversebytes[--count];
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
#endif
if(count == 0) {
reverse = 0;
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
} else {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"copy: %03x ", count);
#endif
}
ch = (*clockfunc)();
//ch = ressu_clockbyte2();
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
newressu_output = 1;
#endif
if(--count == 0) {
reverse = 1;
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
}
#ifdef DEBUG2A
fflush(stdout);
#endif
return(ch);
}
Tässä vielä edellinen ilman #ifdef DEBUG2A rivejä: (debukilla voi muuten katsella miten copy reverse käyttäytyy).
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[256];
static unsigned int count = 0;
if(reverse) {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)();
//reversebytes[c] = ressu_clockbyte2();
}
}
ch = reversebytes[--count];
if(count == 0) {
reverse = 0;
}
} else {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
}
ch = (*clockfunc)();
//ch = ressu_clockbyte2();
if(--count == 0) {
reverse = 1;
}
}
return(ch);
}
Seuraavassa fixed moodissa tehtyjä satunnaisbittejä : (–stat optio tuo tulosteeseen myös kaksi statistics riviä. Huomaa että pisin kellojono on tuo 80 merkkiä, kaikki muut ketjut ovat satunnaisista kohdista katkaistuja saman mittaisia ketjuja)
$ ./newressu --fixedclock --stat
randomsource: ressu, clockmode: 1, clockchainlength: 80, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:10 1:38 2:37 3:25 4:20 5:30 6:37 7:30 8:27 9:25 10:29 11:32 12:19 13:28 14:36 15:31 16:35 17:19 18:31 19:18 20:28 21:28 22:24 23:31 24:25 25:30 26:38 27:29 28:29 29:39 30:27 31:26 32:29 33:24 34:22 35:26 36:24 37:44 38:25 39:32 40:32 41:28 42:21 43:40 44:23 45:23 46:21 47:24 48:27 49:27 50:23 51:33 52:26 53:26 54:31 55:23 56:23 57:28 58:19 59:29 60:22 61:17 62:28 63:20 64:27 65:22 66:29 67:23 68:16 69:24 70:20 71:21 72:23 73:30 74:27 75:26 76:18 77:15 78:27 79:26 80:1041, chains:3156, sorted: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 44 1041, high1:1041, high2:44, lim1a:37, lim1b:38, lim1:37, lim2:38, div:1.027027, clockbytes:163760, rndbits1:1916, rndbits2:16488, rndbits3high:1041, rndbits3:2115, rndbits4highdigits:4, rndbits4:2115, rndbits5:3156, rndbits6high:1041, rndbits6:10576, rndbits7high:1041, rndbits7:21067
00000 22294132938409767835685350193923839292365996595976935862826433282
00001 48488719945788375230776214888393776008587235060334557977496406293
00002 80431275143976461305838453114822706361730974050477594023459017094
00003 93206417217628250656515986177836863340864892051316267057597113916
00004 61731938638333708609330161928363100282423290987243662193954403192
00005 94982923919430464067869481643568801481659685690996569554171263466
00006 73313649799714726811829474731299233472648891876654506268759611113
00007 71330815013503135793796350332802986281525959248136439352537631481
00008 80520675067022116837313859689861210963143997805965619140693304090
00009 27529324544421024520929292748015725933677643980607578142560612229
Sitten DEBUG2A tulostetta normal moodissa: (ch: on palautettava merkki, copy: sanan jälkeen tulee merkkien lukumäärä ja kopioitava blokki, rev: sanan jälkeen merkkien lukumäärä, merkit alkuperäisessä järjestyksessä ja sitten käännetyssä järjestyksessä).
copy: 015 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
rev: 019 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21
ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
copy: 016 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
rev: 00a 21 21 21 21 21 21 21 22 22 22
ch:22 ch:22 ch:22 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
copy: 010 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
rev: 018 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
copy: 014 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
rev: 00f 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
Mielenkiintoista on, voiko teoreettisten satunnaismerkkien laskennan (rndbits1, rndbits3 jne) jättää kokonaan pois kun copy-reverse on toiminnassa, sitä voi yrittää hahmottaa newressu –single komennolla.
$ ./newressu --stat --single
randomsource: single, clockmode: 0, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:1 1:38 2:35 3:6 4:13 5:13 6:9 7:11 8:9 9:9 10:7 11:5 12:7 13:9 14:62 15:169 16:8 17:1 18:6 19:122 20:68, chains:607, clockbytes:8187, rndbits2:1128
00000 32262283161809391678657136366555756828967803578676610526738617216
00001 69511031437775242989469007588191015483302697394274894700778823040
00002 76140983583748585072353786938410170011199037634650689281079597904
00003 93729335401437288771146924781560699584385747294818636367091300176
00004 05265892091793398109092431528679114647250196564188868255370175310
00005 32662058346170613285279049952971968089134474619682155846073978431
00006 37542509108789762598062162668902832635630435392168038872003862287
00007 49867796710786537902924653466617634225652081735463098061052717754
00008 40532647329764438978005136772857284492053527665773437979327537731
00009 68916755542984513818470885899001010383458534877845952219318341042
Vielä fast versio, jossa oletetaan, että copy-reversen 8 bittiä blokki (rndbits2) on oikea satunnaisuuden määrä. Tässä ei siis testata noita muita teoreettisen satunnaisuuden kenttiä:
$ ./newressu --stat --fast
randomsource: fast, clockmode: 0, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:3 1:18 2:19 3:19 4:13 5:11 6:23 7:16 8:18 9:22 10:10 11:18 12:14 13:12 14:11 15:14 16:13 17:14 18:16 19:11 20:16 21:27 22:301 23:99 24:16 25:10 26:13 27:10 28:11 29:7 30:9 31:5 32:72 33:181 34:16 35:11 36:5 37:6 40:3 41:3, chains:1113, sorted: 3 5 6 7 9 10 11 12 13 14 16 18 19 22 23 27 72 99 181 301, clockbytes:24556, rndbits2:1736
00000 68784755242708765294394273037319039572739737000724542275166407714
00001 06972592691192404285861495591371050958299735095969537656132751909
00002 67574262177835663992021063370107991617814973885686637190673088094
00003 23737673519966062499715155344625118562351368088477401742394627022
00004 03263216076372320938776167737005047546185162611650283796001101369
00005 51407508376549070991359975767652992476157609203411915065410641295
00006 12655893530487345584253510097815082335938955217832759445595250214
00007 24937072376561882973994015071952414930388304299234767961731321584
00008 05580710011089642452809116400909876953773223311014848926770989925
00009 80053600376650552642904242376127515525297384309817394907301522152
Joka tapauksessa perusversio: teoreettisten satunnaismerkkien laskemisineen ja copy-reverse:n kanssa on mielestäni versio korotuksen arvoinen. (Teiltä pitäisi kysyä onko se valmis…) Suorittelen kuitenkin, kuten aina, sen käyttämistä muiden generaattorien kanssa, ja viimeinen tietysti omassa ohjelmassa. Näistä omistani –pseudoressu tulee mieleen, siitä jatkossa.
$ ./newressu
00000 37623172794213955845654028970142043156650464162378618125059418215
00001 44770808876162322824064917059041951056355916863064355533513084242
00002 75485713017878047234034253933802355371072968018532606905129869680
00003 96551784242102846132000149967407451652050029473735516535627149942
00004 91453561873005997442161145845169261020298914882602023854201229781
00005 72203425783242175112239728887442139124665422626613641888668562931
00006 01828527840750137347400562529323569375142224887300242484404778626
00007 34038142372693997824692927661290471630937124920642848309126302336
00008 71422612084979552308234145197900652207559401420147297100214334402
00009 64387847336829223605559797922477255813426710680768085663528529936
Vielä ressun “ydin” ja liitännäistoiminnot. Uudelleen nimetty pääfunktio.
#define RR8(byte,bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte,bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )
#define aDEBUG5 2
void ressu_genbytes_single_do(int size, unsigned char *buffer)
{
int c, d;
unsigned char e, byte;
static int f = 0, prevbyte = -1, count = 0;
//ressuct = buffer; // ressu random buffer lookup
//ressuct_bytes = size;
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++;
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout, "\n");
ressu_dump("single 1", 32, buffer, 32);
#endif
for(d = 0; d < size; d++) {
f = (f + buffer[d] + 2) % size; // +2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout,"\n");
ressu_dump("single 2", 32, buffer, 32);
#endif
}
}
Ja uusi versio ressu_genbytes_single() funktiosta, johon on lisättu –stat rivit, ja uusi genbytes_single_do() -kutsu:
Nuo ensimmäiset ressu_ct ja _bytes kertovat paikan josta uusi copy-reverse hakee blokin pituuden. Pituudet haetaan aina käsittelyn alla olevasta satunnaisbittipuskurista.
void ressu_genbytes_single(int size, unsigned char *buffer)
{
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
ressu_genbytes_single_do(size, buffer);
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:1");
long chains = 0;
for(int e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
}
Sitten ressu ressu_genbytes(): jossa lisätyt ressuct ja _bytes muuttujat kellojonon pituuden hakemista varten ja muutettu kutsu ressu_genbytes_single_do “ydintä” varten.
#define aDEBUG7 2
#define aDEBUG2 2
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c, d, e, f;
static unsigned char ressut[RESSUT_BYTES];
static int ressut_first = 1,
ressut_pos = 0,
ressut_f = 0;
unsigned long prevperiods[1024];
#ifdef DEBUG2
static unsigned char counts[RESSUT_BYTES];
#endif
ressuct = ressut; // ressu random buffer lookup
ressuct_bytes = ressut_bytes; // table used in ressu_genbytes_single_do
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 DEBUG2
for(d = 0; d < size; d++)
counts[d] = 0;
#endif
rndbits1 = 0;
rndbits2 = 0;
rndbits3 = 0;
rndbits4 = 0;
rndbits5 = 0;
rndbits6 = 0;
rndbits7 = 0;
int lim, lim1 = 0, lim2 = 0;
int lim1a, lim1b;
int high1, high2;
int rndbits3high;
int rndbits4highdigits;
int rndbits6high;
int rndbits6pos;
int rndbits7high;
for(d = 0;
rndbits1 < ressu_bits1_needed ||
rndbits2 < ressu_bits2_needed ||
rndbits3 < ressu_bits3_needed ||
rndbits4 < ressu_bits4_needed ||
rndbits5 < ressu_bits5_needed ||
rndbits6 < ressu_bits6_needed ||
rndbits7 < ressu_bits7_needed ||
d < RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
#define aDEBUG6 2
//
// calculate rndbits1
//
// save previous round
for(e = 0; e < 1024; e++) {
prevperiods[e] = periods[e];
}
ressu_genbytes_single_do(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 rndbits1
#define aDEBUG6 2
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
}
}
//
// calculate rndbits3
//
#define aDEBUG8 2
rndbits3high = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high < periods[e])
rndbits3high = periods[e];
}
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e]) {
rndbits3 += periods[e];
}
}
//
// calculate rndbits4
//
#define aDEBUG9 2
rndbits4highdigits = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
rndbits4highdigits = (int)log10((double)periods[e]) + 1;
}
}
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
rndbits4 += periods[e];
}
}
//
// calculate rndbits5
//
#define aDEBUG10 2
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
rndbits5 += periods[e];
}
//
// calculate rndbits6
//
#define aDEBUG11 2
rndbits6high = 0;
rndbits6pos = 0;
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high < periods[e]) {
rndbits6high = periods[e];
rndbits6pos = e;
}
}
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] && periodsl[e] > 0) {
if(rndbits6pos > e)
rndbits6 += log2((double)rndbits6pos - e) * periods[e];
else
rndbits6 += log2((double)e - rndbits6pos) * periods[e];
}
}
//
// calculate rndbits7
//
#define aDEBUG12 2
rndbits7high = 0;
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high < periods[e])
rndbits7high = periods[e];
}
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] && periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
}
}
} // for(d=0;
//
// debug display for rndbits1
//
#ifdef DEBUG6
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits1+prev:%d", rndbits1);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits3
//
#ifdef DEBUG8
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e] &&
periods[e] > 0) {
rndbits3 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits3+prev:%d", rndbits3);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits4
//
#ifdef DEBUG9
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1 &&
periods[e] > 0) {
rndbits4 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits4+prev:%d", rndbits4);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits5
//
#ifdef DEBUG10
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
rndbits5 += periods[e];
fprintf(stderr,", rndbits5+prev:%d", rndbits5);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits6
//
#ifdef DEBUG11
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] &&
periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%lu", periods[e]);
double l2;
if(rndbits6pos > e) {
fprintf(stderr,", pos-e:%d", rndbits6pos - e);
l2 = log2((double)rndbits6pos - e);
} else {
fprintf(stderr,", e-pos:%d", e - rndbits6pos);
l2 = log2((double)e - rndbits6pos);
}
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
rndbits6 += l2 * periods[e];
fprintf(stderr,", rndbits6+prev:%d", rndbits6);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits7
//
#ifdef DEBUG12
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] &&
periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", high-prev:%ld", rndbits7high-periods[e]);
double l2=log2((double)rndbits7high-periods[e]);
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
fprintf(stderr,", rndbits7+prev:%d", rndbits7);
fprintf(stderr,"\n");
}
}
#endif
if(stats) {
if(newressu_output == 1)
fprintf(stderr,"\n");
newressu_output = 0;
//
// display statistics
//
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
#ifdef DEBUG_SORTED
fprintf(stderr, ", 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(stderr," %d", g);
}
#endif
fprintf(stderr, ", high1:%d", high1);
fprintf(stderr, ", high2:%d", high2);
fprintf(stderr, ", lim1a:%d", lim1a);
fprintf(stderr, ", lim1b:%d", lim1b);
fprintf(stderr, ", lim1:%d", lim1);
fprintf(stderr, ", lim2:%d", lim2);
fprintf(stderr, ", div:%f", (double)lim2 / lim1);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits1:%d", rndbits1);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, ", rndbits3high:%d", rndbits3high);
fprintf(stderr, ", rndbits3:%d", rndbits3);
fprintf(stderr, ", rndbits4highdigits:%d", rndbits4highdigits);
fprintf(stderr, ", rndbits4:%d", rndbits4);
fprintf(stderr, ", rndbits5:%d", rndbits5);
fprintf(stderr, ", rndbits6high:%d", rndbits6high);
fprintf(stderr, ", rndbits6:%d", rndbits6);
fprintf(stderr, ", rndbits7high:%d", rndbits7high);
fprintf(stderr, ", rndbits7:%d", rndbits7);
fprintf(stderr, "\n");
fflush(stderr);
}
} // 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++)
if(verbose) {
fprintf(stdout,"ressu ");
for(c = 0; c < size; c++) {
if(c > 0 && c % 32 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x", buffer[c]);
newressu_output = 1;
}
fprintf(stdout,"\n");
}
#ifdef DEBUG7
ressu_dump("genbytes", size, buffer, 32);
#endif
genbytes += size;
}
Mielestäni ressu (./newressu –ressu tai ./newressu) on kelvollista jopa one time pad materiaaliksi (jokainen bitti irtonainen, ei ole laskennallista yhteyttä muihin bitteihin paitsi tilastollinen todennäköisyys), ja jos noin olisi voisimme tehdä nopeamman satunnaisgeneraattorin käyttämällä ressua satunnaisbittien lähteenä ja tehdä uusia satunnaisbittejä tiivistefunktiolla (tässä sha256) (vertaa fort). Tässä generattoriehdokas: (ehdokas ei tietenkään ole one time pad materiaalia sha256 funktion vuoksi).
Edit: Miksi sitten ressun bitit ovat riippumattomia. Helpoimmin päättelyni jäljille pääsee, jos kuvittelee että kellomerkit on and:atty ykkösellä. Tällöin vain alin bitti kellojonosta jää jäljelle. Kun and:atyllä kellojonolla xor:ataan puskuri vain sen alin bitti muuttuu. Shift:issä alin bitti siirretään talteen kakkosbittiin ja kakkosbitti kolmosbittiin jne. Merkkien paikkaa muutetaan satunnaisesti ja aloitetaan alusta. Merkkien paikkojen satunnainen muuttaminen poistaa yhteyden yksittäisten “samalla rivillä” olevien bittien välillä. Se että yhden merkin eri bitit otetaan eri kohdasta kellojonosta ja vaihdetusta puskurinpaikasta varmistaa että merkin biteille ei muodostu yhteyttä. (Huomaa että myös merkin paikka puskurissa vaikuttaa siihen mikä merkki kellojonosta otetaan.) Jos tähän lisätään muut bitit (ei tehdä and:iä ykkösellä) muut bitit vain sekoittavat lisää, yhteyttä ei uudestaan synny.
Edit: seuraavassa esimerkki, jossa on listattuna yhdellä and:ätyt puskurien alut: (ensimmäisellä rivillä vain nollabitti, eli arvot 0 ja 1. Seuraavalla rivillä lisätty ykkösbitti eli arvo 2 (tällöin arvot ovat 0 1 2 ja 3). Seuraavalla kakkosbitti (4) eli arvot 0, 1, 2, 3, 4, 5, 6 ja 7. Rivejä on tässä 8 kappaletta eli oma rivi jokaiselle uudelle bitille, viimeisen bitin arvo on 80 eli 128d. Seuraavan listan joissa on single 1 rivillä single_do()-funktion shift ja xor ja single 2 rivillä swap saat DEBUG5:lla. Lista on heksana että voidaan tarkistaa että viimeinen rivi on todella varsinaisella satunnaislukulistalla rivi 1. Huomaa ensimmäisen rivin swap:it. Kun swappailemme merkkejä joissa on vain ykköstä ja nollaa, ilmeni että niissä molemmissa on epäsymmetriaa verrattuna muihin merkkeihin.
$ ./newressu --single -x --fixedclock5| more
single 1 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01
single 2 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01
single 1 02 03 02 02 00 00 01 01 01 03 03 02 02 02 00 00 01 01 01 03 02 03 02 02 00 01 00 01 01 03 03 02
single 2 02 02 01 00 00 01 01 00 01 03 01 01 00 02 01 02 02 01 03 00 00 01 03 03 02 03 00 02 00 02 01 02
single 1 04 05 02 01 01 03 03 00 02 06 02 03 00 05 03 05 05 02 06 00 00 02 07 07 05 07 01 04 00 04 02 05
single 2 07 07 01 06 06 03 05 04 05 03 03 06 00 06 02 02 03 02 06 06 03 00 07 00 02 04 02 00 05 05 04 04
single 1 0f 0f 03 0c 0c 06 0a 08 0a 07 07 0d 01 0d 04 04 06 04 0d 0d 07 01 0f 00 04 08 04 00 0b 0a 08 09
single 2 0b 0f 09 01 01 0b 04 03 05 09 09 08 0d 07 09 05 0a 09 04 0b 04 0f 03 04 0b 04 08 09 08 06 02 0f
single 1 16 1e 12 02 02 17 09 07 0b 13 12 10 1a 0e 12 0b 15 13 09 16 08 1e 06 08 17 09 11 13 11 0c 04 1e
single 2 0f 1f 00 0e 02 15 12 15 09 16 19 16 10 0f 07 19 13 0a 16 1e 05 1b 01 15 08 08 19 0f 1a 0a 16 0a
single 1 1f 3f 01 1d 05 2a 24 2a 12 2c 33 2d 21 1f 0f 32 26 14 2c 3c 0b 37 03 2b 11 10 32 1e 34 14 2d 15
single 2 17 01 28 33 16 19 2b 1f 1f 15 28 2b 35 0f 37 16 32 18 0d 28 27 1f 11 11 3e 0a 3f 10 3b 26 0a 30
single 1 2f 03 50 66 2c 32 56 3f 3f 2b 51 57 6a 1e 6e 2c 64 31 1b 51 4f 3f 22 22 7c 14 7e 21 77 4d 15 61
single 2 56 55 2b 3b 3d 70 22 52 79 6d 52 57 3e 29 24 1e 50 5c 36 13 2a 5b 00 54 43 0f 18 5e 13 5d 21 70
single 1 ad ab 57 76 7a e0 44 a4 f3 db a5 af 7d 52 48 3c a0 b8 6d 27 55 b7 01 a8 86 1e 30 bc 27 bb 43 e1
single 2 41 b1 01 14 dc a8 a2 36 48 a8 6a 97 85 13 62 3f 0b e0 b5 34 8d b9 c4 fa 65 bc 8c 93 b8 f9 f2 ef
00000 41b10114dca8a23648a86a978513623f0be0b5348db9c4fa65bc8c93b8f9f2ef
00001 119f2a30b1a5b7737d92f5ca7d55b2991bca8da85db795278876a0cc66cd7fee
00002 40fe7e3eb56ee10680053fb69f00aa9e05b470490270875180bf545609d55db4
00003 af82f8756838045d6d8b8bf2ada39b43456690bd7ca56cba3fa592ec660680a2
00004 6f4370a240850ad1951fe555c1ef377b0b0fa20af3b1cd5381ac4a2916764eb2
00005 5b59d45d9d19280b9115405c92a25a75cd4c53b051d5df45a0cd4b39163c5060
00006 f4524aad74b97cab5bb6b6ae4baff0b609562aab71ddbd10b9473fb4f0be6940
00007 587979249184244f17740e5a9e4a5047fd46c94b1721fad3ff964363a313b8b3
00008 49724491c0ab1b9933c3a2f83caed2c97ea5482d5f0e5dfc775effde59a40bd4
00009 2a558f2f09776189a4b812fa741b423172ad619853a5eddbc21674a1564c5701
Nolla toimi seuraavalla tavalla: swapissähän f muuttujaan eli swapin kohteeseen lisätään merkki swapin puskurin d:n kohdasta. Jos siis puskuri d:n sisältö (bufferd) on nolla, f ei kasva, ja koko nollia sisältävä ketju jää “ripottelematta” puskuriin. Seuraavassa d käy läpi koko puskurin, f ei muutu mihinkään, ja näin koko nollaketju jää samanlaiseksi. Kun nollaketju loppuu swap:pi palaa takaisin normaaliin toimintaan.
ressu 1 00 00 00 00 00 01 01 01 01 01 00 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00
d:0, f:0, bufferd:0, bufferf:0
d:1, f:0, bufferd:0, bufferf:0
d:2, f:0, bufferd:0, bufferf:0
d:3, f:0, bufferd:0, bufferf:0
d:4, f:0, bufferd:0, bufferf:0
d:5, f:0, bufferd:1, bufferf:0
d:6, f:1, bufferd:1, bufferf:1
d:7, f:2, bufferd:1, bufferf:1
d:8, f:3, bufferd:1, bufferf:1
d:9, f:4, bufferd:1, bufferf:1
d:10, f:5, bufferd:0, bufferf:1
d:11, f:5, bufferd:0, bufferf:0
d:12, f:5, bufferd:0, bufferf:0
Ykkösellä ongelma oli seuraava: d kulkee taas puskurin alusta puskurin loppuun ja f:ää kasvatetaan d:n sisällöllä (bufferd), siis f:ää kasvatetaan yhdellä, tällöin laitetaan ykkönen seuraavaan f:ään, joka on tietenkin seuraava d:n sisältö. Näin f kasvaa joka kierroksella yhdellä kunnes ykkönen on siirretty puskurin viimeiseen merkkiin. Ykkösversio ei siis palaa normaaliksi ykkösten jälkeen vaan jatkuu puskurin loppuun.
ressu 1 01 01 01 01 01 00 00 00 00 00 01 01 01 01 00 01 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01
d:0, f:0, bufferd:1, bufferf:1
d:1, f:1, bufferd:1, bufferf:1
d:2, f:2, bufferd:1, bufferf:1
d:3, f:3, bufferd:1, bufferf:1
d:4, f:4, bufferd:1, bufferf:1
d:5, f:5, bufferd:1, bufferf:1
d:6, f:6, bufferd:1, bufferf:1
d:7, f:7, bufferd:1, bufferf:1
d:8, f:8, bufferd:1, bufferf:1
d:9, f:9, bufferd:1, bufferf:1
d:10, f:10, bufferd:1, bufferf:1
d:11, f:11, bufferd:1, bufferf:1
d:12, f:12, bufferd:1, bufferf:1
d:13, f:13, bufferd:1, bufferf:1
Korjaus on tietenkin ohittaa nämä tapaukset eli kasvattaa f:ää d:n sisällön lisäksi kakkosella. (d muuttujaa ei voi muuttaa, varsinaista swäppiä ei voi muuttaa, datan perusteella ei voi tehdä logiikkaa (esim if data = “1”), joten ainoa vaihtoehto on muuttaa f:ää) Seuraavassa uusi swap:pi osuus:
Ongelma ennen 0 ja 1 muutostakaan ei ollut tilastollisesti kovin yleinen. Suurin osa korjautui sillä että seuraavalla xor:lla nuo nollabitit ja ykkösbitit muuttuvat toisiksi ja taas swappaytyvät normaalisti. Periaatteessa puskurin viimeinen merkki oli hieman useammin ykkönen, joten siitä olisi voinut tehdä tunnistuksen käytetystä ressusta. +2 muutoksen jälkeen tunnistus ei tietenkään onnistu, nyt kaikki dataarvot toimivat uudessa versiossa symmetrisesti. Asiaa on tietysti tutkittava, ja osin uudelleen koska “sydän” (ressu_genbytes_single_do()) on muuttunut.
#define aDEBUG5A 2
#define aDEBUG5B 2
#define aDEBUG5C 2
#define aLOWCLOCKBITONLY 2 // off by default //
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
...
for(d = 0; d < size; d++) {
#ifdef DEBUG5B
fprintf(stdout,"d:%d", d);
fprintf(stdout,", f:%d", f);
fprintf(stdout,", bufferd:%d", buffer[d]);
fprintf(stdout,", bufferf:%d", buffer[f]);
fprintf(stdout,"\n");
#endif
f = (f + buffer[d] + 2) % size; // +2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
...
}
F:än kasvattaminen yhdellä ei riitä, sillä sitten nolla toimii kuten yksi äsken eli kulkee kaikkien puskuripaikkojen läpi puskurin loppuun:
ressu 1 00 00 00 00 00 01 01 01 01 01 00 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00
d:0, f:0, bufferd:0, bufferf:0
d:1, f:1, bufferd:0, bufferf:0
d:2, f:2, bufferd:0, bufferf:0
d:3, f:3, bufferd:0, bufferf:0
d:4, f:4, bufferd:0, bufferf:0
d:5, f:5, bufferd:0, bufferf:0
d:6, f:6, bufferd:0, bufferf:0
d:7, f:7, bufferd:0, bufferf:0
d:8, f:8, bufferd:0, bufferf:0
d:9, f:9, bufferd:0, bufferf:0
d:10, f:10, bufferd:0, bufferf:0
d:11, f:11, bufferd:0, bufferf:0
d:12, f:12, bufferd:0, bufferf:0
d:13, f:13, bufferd:0, bufferf:0
Lista, jossa aiempi ensimmäinen swappirivi oli melkein muuttumaton, tässä se näyttää jo kohtuulliselta (+2 version): Tässä on otettava huomioon että tämä on ensimmäinen swappi puskurille joka sisältää pelkästään ykkösiä ja nollia pitkinä jonoina. Seuraavat swap:it lisäävät tietysti satunnaisuutta.
$ ./newressu --single -x
ressu 1 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00
ressu 2 00 01 01 01 01 00 01 00 01 00 00 01 01 00 01 01 00 00 01 00 01 01 01 01 00 00 00 01 01 01 00 01
ressu 1 01 02 02 02 02 00 02 00 02 01 01 03 03 01 03 03 01 01 03 01 03 03 03 03 01 01 01 03 03 03 01 03
ressu 2 02 00 01 02 03 02 02 01 01 03 01 03 03 00 01 03 01 03 00 01 01 01 01 03 01 03 01 03 01 00 01 02
ressu 1 04 00 02 04 06 05 05 03 03 07 03 07 07 01 03 07 03 07 01 03 03 03 03 07 03 07 03 07 03 01 03 05
ressu 2 00 02 00 06 03 03 03 00 06 00 06 02 01 01 04 02 02 05 01 00 04 03 04 02 01 07 06 05 01 06 02 06
ressu 1 00 04 00 0c 06 06 06 00 0c 00 0c 04 02 02 08 04 04 0b 03 01 09 07 09 05 03 0f 0d 0b 03 0d 05 0d
ressu 2 09 03 0e 03 07 0a 00 08 0b 0f 0a 08 07 0e 08 0c 08 07 0a 0d 05 05 08 06 02 0b 01 04 07 0c 0d 0d
ressu 1 13 07 1d 07 0f 15 01 11 17 1f 15 11 0f 1d 11 19 11 0f 15 1b 0b 0b 11 0d 05 17 03 09 0f 19 1b 1b
ressu 2 15 1b 0d 05 0f 1c 04 0c 01 1f 1b 05 07 0d 18 19 04 04 10 06 08 18 14 08 0a 0e 1c 1e 04 15 15 1a
ressu 1 2a 36 1a 0a 1e 38 08 18 02 3f 37 0b 0f 1b 31 33 09 09 21 0d 11 31 29 11 15 1d 39 3d 09 2b 2b 35
ressu 2 27 0f 16 25 24 05 02 0b 37 0d 36 20 1b 0c 08 2e 3b 22 29 30 27 01 28 16 02 05 2b 1c 08 2b 0a 33
ressu 1 4e 1e 2c 4a 48 0a 04 16 6e 1a 6c 40 36 18 10 5c 76 44 52 60 4e 02 50 2d 05 0b 57 39 11 57 15 67
ressu 2 7f 5c 6a 0a 47 3b 40 21 2e 5a 29 0e 3f 12 60 23 4b 45 37 73 77 53 3e 42 70 68 20 49 52 25 58 57
ressu 1 fe b8 d4 14 8e 76 80 42 5c b4 52 1d 7f 25 c1 47 97 8b 6f e7 ef a7 7d 85 e1 d1 41 93 a5 4b b1 af
ressu 2 87 ee b4 41 69 fc 4e 70 0a b3 d6 46 73 40 a0 0c 01 76 64 73 7e 98 0c e3 9a e3 3e b1 c2 b4 88 e2
00000 87eeb44169fc4e700ab3d6467340a00c017664737e980ce39ae33eb1c2b488e2
00001 1a6ea6583d89530e1e1455442446f3cf1ef119d28334f674db7ac30757fd0691
00002 b777adfc58cf9d4bdf8029a6df98ffd44aa4adfc52675306e72a38193a337da7
00003 c184bde3d90783c51df7ae206a245449f4c9ad78f2fa052c2113543c69753cf0
00004 c600776f4299a0729aabac97cc07956a6c3b616b499430c7c6165bbba81febaf
00005 e817ad5bece64ffcb8a7ca1b1d85a3b2eebbec925403d802c11612e99914531e
00006 619a2e82b7b321608dbf28d67044b542e2bdc3428d098430662f639c5af26963
00007 e76d4bf95ddd078a958bd537deb70bce2d6df7f8a0b49aa326565e64161acbbb
00008 736d9bbcae75d5037da8c545b78ff0042ee45b6a337384b8c389276ab7db962f
00009 94f2f4ef5cd97591af58c3e4669f64386d05f8cc890eb49946ed451372278168
Koko ensimmäinen swap:ätty blokki DEBUG5c päällä:
ressu 3 01 00 01 01 01 01 00 00 01 01 00 00 00 00 01 01 01 01 01 01 01 01 00 01 00 01 01 01 00 01 01 00
ressu 3 01 01 00 00 00 01 01 00 00 00 00 01 01 01 00 00 00 00 00 01 01 00 00 01 00 00 01 00 01 01 00 01
ressu 3 00 01 01 01 01 00 00 00 00 00 01 00 00 00 00 00 00 01 00 00 01 00 01 00 01 01 00 01 00 01 00 01
ressu 3 01 00 00 00 00 00 01 00 01 01 00 00 00 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 01 01 00 01
ressu 3 01 01 01 01 01 01 01 01 01 01 01 01 01 00 01 01 00 01 01 00 01 01 00 00 01 01 01 01 01 01 01 01
ressu 3 01 01 01 01 01 01 00 00 00 00 01 00 00 01 00 01 01 01 01 01 01 00 01 01 01 01 00 01 00 01 01 00
ressu 3 00 00 00 00 01 01 00 00 00 00 01 01 01 00 00 01 01 01 00 01 00 00 00 00 00 00 00 00 01 00 00 01
ressu 3 00 00 01 00 01 00 01 00 01 00 00 01 00 00 00 00 01 00 00 01 00 00 01 00 01 01 01 01 00 00 01 00
ressu 3 01 00 01 00 00 00 00 00 00 01 00 01 01 00 00 01 01 01 00 01 00 01 01 00 01 00 01 00 01 00 00 01
ressu 3 00 01 01 00 00 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 01 00 01 00 00 01 01 00 01 01 00
ressu 3 01 00 01 00 01 01 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00 01 00 01 01 01
ressu 3 00 00 00 00 00 00 00 00 00 01 01 01 00 01 00 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 00
ressu 3 00 01 00 00 01 00 00 00 01 00 01 01 01 01 00 01 00 01 01 00 01 00 00 01 01 01 01 00 01 01 01 01
ressu 3 01 01 00 00 01 01 01 01 01 01 01 01 00 01 01 01 01 01 00 00 01 01 00 01 01 01 00 01 01 01 00 00
ressu 3 01 00 01 01 01 01 01 00 01 01 01 01 01 00 01 00 01 00 01 01 01 00 01 00 00 00 00 00 01 01 01 00
ressu 3 01 01 00 01 00 01 00 01 01 01 00 00 00 01 01 00 01 00 00 00 01 01 00 00 01 01 00 01 00 01 00 01
ressu 3 00 00 00 01 01 00 01 00 00 00 01 01 00 01 00 00 00 00 00 01 01 01 01 01 01 01 00 00 00 00 01 01
ressu 3 00 01 01 01 00 00 00 00 01 01 00 01 01 01 01 00 00 00 01 00 00 01 01 01 01 00 00 00 01 01 00 00
ressu 3 01 01 00 00 01 00 01 01 00 00 01 01 00 01 01 00 01 01 00 01 01 00 00 01 01 01 00 00 00 00 01 00
ressu 3 00 00 01 01 00 00 00 01 00 00 00 01 00 00 00 01 00 01 01 00 00 00 01 00 00 00 01 00 00 00 00 01
ressu 3 01 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 00 01 00 00 01 01 01
ressu 3 00 01 01 01 01 00 01 01 01 01 01 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 01
ressu 3 01 01 01 01 01 01 01 01 01 01 00 01 00 00 00 00 00 00 00 00 00 01 01 01 01 00 01 00 01 01 01 01
ressu 3 01 00 01 00 00 00 01 01 01 01 01 01 01 01 01 00 01 01 01 01 01 01 00 01 00 00 00 00 00 00 00 00
ressu 3 01 00 00 00 01 01 01 01 01 01 01 00 01 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 01 01 00
ressu 3 01 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 01 01 01 01 01 01 00 00 00 00 00 01 01 01
ressu 3 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 01 00 01 01 00 01 01 00 00 00 01 01 01 01 01 00 00
ressu 3 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01 01 01 01 00 00
ressu 3 00 00 00 00 01 01 01 00 01 00 00 00 00 00 01 01 01 01 01 01 00 00 00 00 01 01 01 01 00 01 00 00
ressu 3 00 01 00 01 01 01 01 00 00 00 01 01 01 01 00 00 00 00 00 00 00 01 01 01 00 00 01 00 00 00 00 01
ressu 3 00 00 00 00 01 00 00 00 00 01 01 00 00 01 01 01 01 00 00 00 00 00 01 00 00 01 00 00 01 01 00 00
ressu 3 01 01 00 00 01 00 00 01 00 01 00 00 01 00 00 00 01 00 00 00 01 01 00 00 00 00 00 00 00 00 00 01
Edellistä DEBUG5C:llä tehtyä blokkia voi tietenkin verrata seuraavaan ressulla tehtyyn blokkiin:
$ ./newressu -w32 -l32 --lim2 -x
00000 0 0 0 1 0 0 0 0 0 1 0 1 1 0 1 0 1 0 0 1 0 1 0 1 1 0 1 0 0 1 1 0
00001 1 0 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 0 1 0 1 0 1 1 0 0
00002 1 0 1 0 1 0 0 1 1 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1
00003 1 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 0
00004 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 0 1 1 0 1
00005 1 0 1 0 1 1 0 1 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0
00006 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 1 0 0 0 0 1 1 1 1 0
00007 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 1
00008 0 0 1 1 0 1 1 0 1 0 0 1 0 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
00009 1 1 1 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1
00010 0 1 0 0 0 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 0 0 0 1 1 0 0 1 1 0 0 1
00011 0 1 1 0 0 1 1 1 0 1 0 0 0 0 1 1 1 0 1 1 0 1 1 0 0 0 1 0 0 1 0 0
00012 0 1 0 0 1 1 1 1 0 1 1 0 0 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0 0 1 1
00013 0 1 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 1 0 1 1 1 1
00014 1 0 0 0 0 0 1 0 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 0 1 1 0 0 1 1 1 1
00015 1 1 1 0 1 1 1 1 0 0 1 0 0 0 0 1 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 1
00016 0 0 1 0 1 1 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0
00017 0 0 1 1 0 1 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 1
00018 1 0 0 1 1 1 1 0 1 0 0 1 0 0 0 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 0 0
00019 0 1 1 1 0 1 1 1 1 0 0 1 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0
00020 0 1 0 0 0 1 1 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0
00021 1 1 1 1 0 0 1 1 1 1 0 1 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 1 0
00022 1 0 0 0 1 0 1 0 0 0 1 1 1 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 1 1
00023 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 1 1 1 1 0 1 0 0
00024 0 1 0 1 0 0 0 1 0 1 0 0 0 1 1 1 1 1 1 1 0 0 1 0 1 1 0 0 0 0 1 0
00025 0 1 1 1 1 0 0 1 0 0 1 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1 1 1 1 0 0 1
00026 1 1 0 0 0 1 0 0 1 1 1 0 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 1 0
00027 0 0 1 0 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 0 0
00028 0 1 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 1 1 0
00029 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1 1 0 0 0
00030 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1
00031 1 0 1 1 1 1 1 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 0 1 1
Vihdoinkin pseudoressu:n koodi:
#define PSEUDORESSU_LIMIT 1048576 // limit between rekeys
#define TOPUP_BYTES 32*1024 // bytes between topups
#define TOPUP_SIZE 32 // topup size in bytes (256 bits)
#define aTOPUP_TWICE 2
static unsigned char pseudoressu_key[HashLen]; // 32 bytes, 256 bits
static void pseudoressu_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash));
}
static void pseudoressu_addrandomness(int size, unsigned char *buffer)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashUpdate(&hash, buffer, size);
HashFinal(pseudoressu_key, &hash);
memset(&hash, 0, sizeof(hash));
}
#define aDEBUG23 2
static void pseudoressu_topup()
{
unsigned char topup[TOPUP_SIZE]; // 256 bits
ressu_genbytes(sizeof(topup), topup);
#ifdef DEBUG23
ressu_dump("topup", sizeof(topup), topup, 32);
#endif
pseudoressu_addrandomness(sizeof(topup), topup);
memset(&topup, 0, sizeof(topup));
}
void pseudoressu_bytes(int size, unsigned char *buffer) // JariK 2022
{
unsigned int n, blockbytes = 0;
unsigned char digest[HashLen]; // 256 bits
static int init = 1, topup_counter = 0;
if(verbose)
fprintf(stdout,"pseudoressu");
while(size > 0) {
if(topup_counter <= 0) {
if(init) {
ressu_genbytes(sizeof(pseudoressu_key), pseudoressu_key); // set first key
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
init = 0;
}
pseudoressu_topup(); // add randomness to key
#ifdef TOPUP_TWICE
pseudoressu_topup(); // add randomness to key
#endif
topup_counter = TOPUP_BYTES;
blockbytes = 0;
} // end of if(topup_counter <= 0)
pseudoressu_internalbytes(digest); // get random bits using the key
n = (size < sizeof(digest) ? size : sizeof(digest));
#ifdef DEBUG23
ressu_dump("olddata", n, buffer, 32);
ressu_dump("bytes", n, digest, 32);
#endif
for(int c = 0; c < n; c++)
buffer[c] ^= digest[c];
#ifdef DEBUG23
ressu_dump("newdata", n, buffer, 32);
#endif
if(verbose) {
fprintf(stdout," ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
newressu_output = 1;
}
buffer += n;
size -= n;
blockbytes += n;
if(blockbytes >= PSEUDORESSU_LIMIT && size > 0) {
pseudoressu_internalbytes(pseudoressu_key); // replace key with new one
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
blockbytes = 0;
}
topup_counter -= n;
} // end of while(size>0)
pseudoressu_internalbytes(pseudoressu_key); // replace key with new one
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
}
Satunnaislukuja käyttäen pseudoressua:
$ ./newressu --pseudoressu
00000 84853369290958902675757388129617632217440385931707856776591439954
00001 84069858194199352061363652567853332957999714525446940392234062860
00002 06427212315998791561126209640856360958935692530455051657986936746
00003 99723974440113428246576863396953005265581100052913290239102752500
00004 63388725437541198987187227629631506871622828013283331007442216631
00005 62030931043545661111647127241062935062281796958567659952167029594
00006 47921575029802383061270050124800729975762794596462783830401317795
00007 52987926964317577756871259541040138838013643538942551182236203384
00008 24214738687464482704041761961902906703331010263554656580505243598
00009 70022632015150824436120131748799624755065262077649254711408046279
Newressu:un on lisätty –rdrand ja –rdseed kytkimet, jotka antavat satunnaisbitit käyttäen Intel (ja Amd) -piirien sisäistä satunnaislukuominaisuutta.
Aluksi määritellään fort.h:ssa käytetäänkö prosessorin satunnaisbittitoimintoa: Voit itse arvioida haluatko käyttää niitä ja poistaa ‘a’:t #define kentän nimen alusta.
...
#define aUSE_RDRAND 2
#define aUSE_RDSEED 2
...
Sitten komentorivikytkimet ohjelman parametreista:
int main(int argc, char *argv[])
{
...
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strncmp("-", argv[c], 1)) {
...
#ifdef USE_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
#endif
#ifdef USE_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
#endif
...
}
Tässä newressu_genbyte(), jolla luetaan yksi satunnaismerkki:
int newressu_genbyte()
{
...
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(sizeof(gent), gent);
#endif
...
}
Sitten edellisen kutsumat rdrand_bytes() ja rdseed_bytes() ja niihin liittyvät funktiot:
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 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 c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"Intel rdrand");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"AMD rdrand");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 100) {
if((ret = _rdrand_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %016lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
newressu_output = 1;
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x", ((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout, "\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDRAND
#ifdef 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 c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"Intel rdseed");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"AMD rdseed");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 1000) {
if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x",((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDSEED
Malliksi satunnaismerkkejä käyttäen –rdrand kytkintä:
$ ./newressu --rdrand
00000 57048164604700389892252604030891636280086112647667058413598950180
00001 85367873337798713870018921407256662622610378059375065346728579858
00002 40986136534533462054903474522649995512196495543741784079574936983
00003 19055247425244842196365427052268075190944922987923879712193930459
00004 21073317923966805747341619816756386934943889348941261188118170090
00005 84441244015826068846216962049544449876189313909490716280827133529
00006 89457709125843616301547827199781195854625633078477767222494900843
00007 26441810410958757585870825129671642480172920546092127710214865492
00008 92825666443631689925831354003095669316518706333179728966151922253
00009 38425570261919457665391336241936521204556331228537091197184239827
Vielä satunnaismerkkejä käyttäen –rdseed kytkintä
$ ./newressu --rdseed
00000 12575858142151541705315577158406477909851976391447353896413900561
00001 31060686344418670883795387123181915659843252785862515386243566233
00002 37717242735083622828533570787786938380359683416949578017028253663
00003 76962160083573864191170336613298614371660291690167147688816903087
00004 97599344559430802834845481925548516864857260161367980227215829024
00005 12924393487151440110103592153782827999940152135987584643269997020
00006 42239941915393566338139392085782443821230059081997751313044879649
00007 84190993998746466726787014147375771575146210681898092888312165521
00008 57327160340778195555246548554777557059408338779546380301502448897
00009 04224922038814950584933722703301666911868454852489894234206320375
Lisätty hindi satunnaislukuaakkosiin kieliin:
$ ./newressu --hin
00000 पठझुनफञौि्ीरमञपआिनरवफहनसजकगढटणथइॉउघयथईवशऔछऔठदौेॉि्झलऊऊडछरखॉऐठुथड
00001 ॉशौाृॅफीऊःनऋकनीौनभठरसॅतचचमठझखफऑरषढगॅीनअटजईचठँऐबरभवॉोपूबे्लञकबअइफ
00002 उ्चीएहःणॅभयरैऐणखलुऋिचौौःढईझोँखफगभशऐछऊइघृउकवगउषटआड़पभछफटॉखथौ़उबीठ
00003 हटऋहथफमगौूउएंौजेेलएौषकऐइरएैपवदमधॅचऊखचिचगधवबमटवगमईआअ्ढ्ःभोचलटथ़ऋए
00004 ीिफतंटप्ीिडँभवदगः्मगऋएगआकऐश्आढऑेअचमणसऐसोइर्ेएयकौीघझथफककःणछओीएॅबद
00005 अटिढछधेऋठऑऔएछॅझढिृतॅधखऋाफणधपइचणेकबछईॅेञ़ढविंकगऋऑतजीुतबइ़्छुछईओधफ
00006 धऋथाइञगगअठओयौवटगएॅेगऑऐडएएञञटवॉतँॉिजामठुढऑलशछदउछॉठटजणूयगौैैीशघेॉझ
00007 डऋकनकउअआऐ़जनअषऊाञिइजीउगंचल़ँबठीमफठॅडहईऑतहंवटतंऊिधखोऋणाओृजञकखऋेएी
00008 ंओण़ुचषछषओञएफचऑौजूऋफानअइठठठइॅआउंऊइऊवौँतवटडषरछघपःइऋचझहँऔझःएछऔीजवक
00009 ँएऑडइॉऔ़्िमृओमादईुणठेघकधेकओकाचमशखऋृँखशढबोफुवलताॅैरझफदखऑझॉशघृँनेघ
Vielä koodi newressuun:
...
} else if(!strcmp("--ind", argv[c])
||!strcmp("--hin", argv[c])) { // Hindi alphabet
digits=" ँ ंःअआइईउऊऋएऐऑओऔकखगघचछजझञटठडढणतथदधनपफबभमयरलवशषसह़ािीुूृॅेैॉोौ ्ाकेरहसनींमि ्तपलोयैबदवुजएगचथअऔूउशडख़भआटछधफइँषघईझठौणॉओृढऊऐऑञः ॅऋ";
//digits = NULL;
//digits_add_limits(&digits,0x900,0x97f); // Hindi (0900-097f)
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
}
...
Koodaamisen lisäksi tutkin ressun tuottamaa satunnaisuutta parilla ohjelmalla (koodasin ne tietysti myös). Tässä ensimmäinen: Ennen sen nimi oli cstat, uusi nimi on newressutest7.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "cstat/newressutest7 version 0.2 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
void main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1, ctrl = 1, chars = 1,
cdiff = 1, cstats = 1, multiple1 = 1, m1expect = 1,
m1diff = 1, multiple2 = 1, m2expect = 1, m2diff = 1,
m2dist = 1, monobit = 1, poker2 = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
cstats = all;
multiple1 = all;
m1expect = all;
m1diff = all;
multiple2 = all;
m2expect = all;
m2diff = all;
m2dist = all;
monobit = all;
poker2 = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--cstats", argv[c])) {
cstats = !cstats;
} else if(!strcmp("--m1", argv[c])) {
multiple1 = !multiple1;
m1expect = !m1expect;
m1diff = !m1diff;
} else if(!strcmp("--multiple1", argv[c])) {
multiple1 = !multiple1;
} else if(!strcmp("--m1expect", argv[c])) {
m1expect = !m1expect;
} else if(!strcmp("--m1diff", argv[c])) {
m1diff = !m1diff;
} else if(!strcmp("--m2", argv[c])) {
multiple2 = !multiple2;
m2expect = !m2expect;
m2diff = !m2diff;
m2dist = !m2dist;
} else if(!strcmp("--multiple2", argv[c])) {
multiple2 = !multiple2;
} else if(!strcmp("--m2expect", argv[c])) {
m2expect = !m2expect;
} else if(!strcmp("--m2diff", argv[c])) {
m2diff = !m2diff;
} else if(!strcmp("--m2dist", argv[c])) {
m2dist = !m2dist;
} else if(!strcmp("--monobit", argv[c])) {
monobit = !monobit;
} else if(!strcmp("--poker2", argv[c])) {
poker2 = !poker2;
} else {
fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
// print help message if needed
if(help) {
fprintf(stderr,"%s",procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--cstats]");
fprintf(stderr," [--multiple1]");
fprintf(stderr," [--m1expect]");
fprintf(stderr," [--m1diff]");
fprintf(stderr," [--multiple2]");
fprintf(stderr," [--m2expect]");
fprintf(stderr," [--m2diff]");
fprintf(stderr," [--monobit]");
fprintf(stderr," [--poker2]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename,"-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
int currentchar = 0;
unsigned char prevchars[MAX];
unsigned long int m1counts[MAX];
unsigned long int m2counts[MAX];
for(c = 0; c < MAX; c++) {
prevchars[c] = 0;
m1counts[c] = 0;
m2counts[c] = 0;
}
unsigned long int singles = 0;
int ch, lastch, prevch;
unsigned long m2length;
first = 1;
// read input file and calculate
// statistics
while((ch = fgetc(fp1)) != EOF) {
if(verbose) {
fputc(ch, stdout);
}
lastch = ch;
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) // ctrl or space, skip
continue;
// calculate m1 multiple
// counts
prevchars[currentchar] = ch;
for(c = 0; c < MAX; c++) {
d = currentchar - c;
if(d < 0)
d += MAX;
if(ch != prevchars[d])
break;
m1counts[c]++;
}
if(++currentchar >= MAX)
currentchar -= MAX;
// calculate m2 multiple
// counts
if(first) {
prevch = ch;
m2length = 1;
first = 0;
} else {
if(prevch == ch) {
m2length++;
} else {
prevch = ch;
m2counts[m2length - 1]++;
m2length = 1;
}
}
singles++;
} // end of while((ch = fgetc(fp1)) != EOF)
if(singles > 0)
m2counts[m2length - 1]++; // add last m2 multiple
if(lastch != '\n') // last char not lf, print lf
fputc('\n', stdout);
fflush(stdout);
if(singles==0) {
fprintf(stderr,"%s: no data\n",procname);
exit(2);
}
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
}
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(ctrl)
// print character counts if needed
long int charsmin = LONG_MAX;
long int charsmax = LONG_MIN;
if(chars) {
long int allchars;
fprintf(stdout,"chars ");
first = 1;
allchars = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%lu", charcounts[c]);
allchars += charcounts[c];
if(charsmin > charcounts[c])
charsmin = charcounts[c];
if(charsmax < charcounts[c])
charsmax = charcounts[c];
first = 0;
}
}
fprintf(stdout,", total:%ld", allchars);
fprintf(stdout,", min:%ld", charsmin);
fprintf(stdout,", max:%ld", charsmax);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(chars)
// calculate character statistics
unsigned long int ctotal = 0, count = 0, average = 0,
characters = 0, utf8first = 0, utf8other = 0,
asciicnt = 0, ctrlcnt = 0;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c < 0x20) { // ctrl, count & skip
ctrlcnt += charcounts[c];
continue;
}
if(c < 0x80)
asciicnt += charcounts[c];
if(c == 0x20) // space, skip
continue;
ctotal += charcounts[c];
count++;
if(c < 0x80 || c > 0xbf) // ascii or utf8 first char
characters += charcounts[c];
if(c > 0xbf) // utf8 first char
utf8first += charcounts[c];
if(c >= 0x80 && c <= 0xbf) // utf8 other char
utf8other += charcounts[c];
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
double entropy = 0;
// calculate entropy
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20) // ctrl or space, skip
continue;
if(charcounts[c] > 0)
entropy += (double)charcounts[c] / ctotal * log2((double) charcounts[c] / ctotal);
}
if(entropy < 0)
entropy = -entropy;
// calculate average
average = ctotal / count;
// calculate character differences
if(cdiff) {
fprintf(stdout,"cdiff ");
long int chardiff = 0;
long int chardifftotal = 0;
long int chardiffmin = LONG_MAX;
long int chardiffmax = LONG_MIN;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%ld", average - charcounts[c]);
chardiff = (average - charcounts[c]);
chardifftotal += chardiff;
if(chardiffmin > chardiff)
chardiffmin = chardiff;
if(chardiffmax < chardiff)
chardiffmax = chardiff;
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,", total:%ld", chardifftotal);
fprintf(stdout,", min:%ld", chardiffmin);
fprintf(stdout,", max:%ld", chardiffmax);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cdiff)
// print character statistics
if(cstats) {
fprintf(stdout,"cstats ");
fprintf(stdout,"min:%ld", charsmin);
fprintf(stdout,", max:%ld", charsmax);
fprintf(stdout,", total:%lu", ctotal);
fprintf(stdout,", count:%lu", count);
if((double)ctotal / count != ctotal / count)
fprintf(stdout,", average:%f", (double)ctotal / count);
else
fprintf(stdout,", average:%ld", ctotal / count);
fprintf(stdout,", characters:%lu", characters);
fprintf(stdout,", utf8first:%lu", utf8first);
fprintf(stdout,", utf8other:%lu", utf8other);
fprintf(stdout,", ascii:%lu", asciicnt);
fprintf(stdout,", ctrl:%lu", ctrlcnt);
fprintf(stdout,", entropy:%f", entropy);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cstats)
// print statistics on m1 multiples
if(multiple1) {
fprintf(stdout,"multiple1 ");
long int total = 0;
for(c = 0; c < MAX; c++) {
if(m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
fprintf(stdout,":%lu", m1counts[c]);
total += m1counts[c];
}
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple1)
// expected m1 multiple statistics
if(m1expect) {
fprintf(stdout,"m1expect ");
long int expect;
long int expectall = 0;
expect = singles;
for(c = 0; c < MAX; c++) {
if(expect > 0 || m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
fprintf(stdout,":%lu", expect);
expectall += expect;
}
if(count == 1)
break;
expect /= count;
}
fprintf(stdout,", total:%ld", expectall);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m1expect)
// difference between statistics and
// real m1 counts
long int min;
long int max;
if(m1diff) {
fprintf(stdout,"m1diff ");
min = LONG_MAX;
max = LONG_MIN;
long int expect;
long int diffall = 0;
expect = singles;
for(c = 0; c < MAX; c++) {
if(expect > 0 || m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
long int temp = expect - m1counts[c];
fprintf(stdout,":%ld", temp);
diffall += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
expect /= count;
}
if(count == 1)
break;
}
fprintf(stdout,", total:%ld", diffall);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // if(m1diff)
// print statistics on m2 multiples
if(multiple2) {
fprintf(stdout,"multiple2 ");
unsigned long int total = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", m2counts[c]);
total += m2counts[c] * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%lu",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple2)
unsigned long int m2expects[MAX];
double base;
for(c = 0; c < MAX; c++) {
m2expects[c] = 0;
}
base = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
if(base * ctotal > 0) {
m2expects[c] = (unsigned long int) (base * ctotal);
base *= ((double)1 / count);
}
}
// expected m2 multiple statistics
if(m2expect) {
fprintf(stdout,"m2expect ");
long int expectall = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c]> 0 || m2expects[c]) {
if(!first)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", m2expects[c]);
expectall += m2expects[c] * (c + 1);
first = 0;
}
}
fprintf(stdout,", total:%lu", expectall);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m2expect)
// difference between statistics and
// real m2 counts
if(m2diff) {
fprintf(stdout,"m2diff ");
min = LONG_MAX;
max = LONG_MIN;
long int diffall = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0 || m2expects[c] > 0) {
if(!first)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
long int temp = m2expects[c] - m2counts[c];
fprintf(stdout,":%ld", temp);
diffall += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
}
fprintf(stdout,", total:%ld", diffall);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m2diff)
if(m2dist) {
fprintf(stdout,"m2dist ");
unsigned long int total;
first = 1;
total = 0;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", ctotal / m2counts[c]);
total += m2counts[c] * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%lu",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple2)
#define aDEBUG84 2
// print monobit statistics if needed
if(monobit) {
unsigned long monobitzeroes = 0;
unsigned long monobitones = 0;
if(count == 2 && charcounts['0'] > 0 && charcounts['1'] > 0) {
monobitzeroes += charcounts['0'];
monobitones += charcounts['1'];
}
int ok = 0;
if(count == 16) {
unsigned char hex[] = "0123456789abcdef";
ok = 1;
for(c = 0; c < strlen(hex); c++) {
if(charcounts[hex[c]] < 1)
ok = 0;
}
if(ok) {
for(c = 0; c < strlen(hex); c++) {
#ifdef DEBUG84
fprintf(stdout,"c:%3d", c);
fprintf(stdout,", count:%ld", charcounts[hex[c]]);
fprintf(stdout,", bits:");
for(d = 3 ; d >= 0; d--) {
fprintf(stdout,"%1d", (c >> d & 1));
}
#endif
for(d = 0 ; d < 4; d++) {
monobitzeroes += charcounts[hex[c]] * !(c >> d & 1);
monobitones += charcounts[hex[c]] * (c >> d & 1);
}
#ifdef DEBUG84
fprintf(stdout,", zeroes:%ld", monobitzeroes);
fprintf(stdout,", ones:%ld", monobitones);
fprintf(stdout,"\n");
#endif
}
}
} // end of if(count == 16)
if(ok) {
fprintf(stdout,"monobit ");
fprintf(stdout,"0:%ld", monobitzeroes);
fprintf(stdout,", 1:%ld", monobitones);
fprintf(stdout,", total:%ld", monobitzeroes + monobitones);
fprintf(stdout,"\n");
}
fflush(stdout);
} // end of if(monobit)
#define aDEBUG87 2
// print poker2 statistics if needed
if(poker2) {
unsigned long poker2[4];
for(c = 0; c < sizeof(poker2); c++)
poker2[c] = 0;
int ok = 0;
if(count == 16) {
unsigned char hex[] = "0123456789abcdef";
ok = 1;
for(c = 0; c < strlen(hex); c++) {
if(charcounts[hex[c]] < 1)
ok = 0;
}
if(ok) {
for(c = 0; c < strlen(hex); c++) {
#ifdef DEBUG87
fprintf(stdout,"c:%3d", c);
fprintf(stdout,", count:%ld", charcounts[hex[c]]);
fprintf(stdout,", bits:");
for(d = 3 ; d >= 0; d--) {
fprintf(stdout,"%1d", (c >> d & 1));
}
#endif
for(d = 0 ; d < 2; d++) {
poker2[c >> (d * 2) & 3] += charcounts[hex[c]];
}
#ifdef DEBUG87
fprintf(stdout,", poker2 ");
first = 1;
for(d = 0 ; d < 4; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"%d:%ld", d, poker2[d]);
first = 0;
}
fprintf(stdout,"\n");
#endif
} // end of for(c = 0; c < strlen(hex); c++)
} // end of if(ok)
} // end of if(count == 16)
if(ok) {
long int total = 0;
fprintf(stdout,"poker2 ");
first = 1;
for(d = 0; d < 4; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"%d:%ld", d, poker2[d]);
total += poker2[d];
first = 0;
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
} // end of if(ok)
fflush(stdout);
} // end of if(poker2)
}
Seuraavassa ohjelman tuloste 8 merkkiä pitkille heksajonoille, joita on kahdeksan kappaletta. Tulosteelle tulostetaan 1000 riviä: “ctrl” rivillä on kontrollimerkkien määrät tässä LF (linefeed, rivinvaihto) merkkejä on yksi jokaiselle riville eli 1000 kpl. Seuraava “chars” rivi listaa materiaalissa olleet merkit. Tässä merkit ovat heksaa eli merkkilaskureita on 16 kpl, nollasta viiteentoista (f). “cdiff” rivillä on erotus keskiarvoon (4000). “cstats” rivillä on erilaisia tilastollisia lukuja.
Entropy lähenee tässä nelosta, koska yhdessä heksamerkissä on 4 bittiä (1, 2, 4 ja 8). Kasvattamalla rivimäärää entropy saavuttaa nelosen.
“multiple1” listaa materiaalissa olevien eri pituisten monikkojen määrän. “m1expect” kertoo eri monikkojen odotetun tilastollisen määrän. “m1diff” kertoo edellisten erotuksen. “multiple2”, “m2expect” ja “m2diff” ovat samalla tavalla monikkojen lukumääriä, mutta ne eroavat siten, että ykkösluvuissa merkki voi kuulua useampaan monikkoon. Merkki (esim ‘2’) voi kuulua kolmosmonikkoon (esim ‘222’), kakkosmonikkoon (’22’) ja ykkösmonikkoon. Toisin sanoen kolmosmonikko (‘222’) sisältää kolme ykkösmonikkoa (‘2′) (singles), kaksi kakkosmonikkoa (’22’) (twins) ja yhden kolmosmonikon (‘222’) (triplets). Kakkosvaihtoehdossa merkki voi kuulua vain yhteen monikkoon.
“m1expect” ja “m2expect”, tilastolliset rivimäärät, lähenevät havaittuja rivimääriä “multiple1” ja “multiple2” materiaalin kasvaessa, ja osan erotuksista “diff” pitäisi olla negatiivisia ja osan positiivisia. Kaavat tilastollisille määrille ovat tietysti ohjelmassa, mielestäni ne ovat aika lähellä oikeita.
Huomaa, että tässä monikot voivat jatkua yli välilyönnin tai rivinvaihdon.
$ ./newressu --single --lineno -x -s8 -w8 -l1000 | ./cstat
ctrl LF:1000
chars 0:4052, 1:3863, 2:4019, 3:3964, 4:4021, 5:4007, 6:4015, 7:4119, 8:3955, 9:3877, a:3929, b:4114, c:4061, d:3987, e:4060, f:3957, total:64000
cdiff 0:-52, 1:137, 2:-19, 3:36, 4:-21, 5:-7, 6:-15, 7:-119, 8:45, 9:123, a:71, b:-114, c:-61, d:13, e:-60, f:43
cstats min:3863, max:4119, total:64000, count:16, average:4000, characters:64000, utf8first:0, utf8other:0, ascii:64000, ctrl:1000, entropy:3.999767
multiple1 singles:64000, twins:3944, triplets:227, quadruplets:12, total:68183
m1expect singles:64000, twins:4000, triplets:250, quadruplets:15, total:68265
m1diff singles:0, twins:56, triplets:23, quadruplets:3, total:82
multiple2 singles:56339, twins:3502, triplets:203, quadruplets:12, total:64000
m2expect singles:56250, twins:3515, triplets:219, quadruplets:13, total:63989
m2diff singles:-89, twins:13, triplets:16, quadruplets:1, total:-59
monobit 0:127768, 1:128232, total:256000
poker2 0:31987, 1:31896, 2:31898, 3:32219, total:128000
Seuraavassa ajossa satunnaislukujen välissä on välilyöntejä (–space), jolloin ctrl riville tulostuu myös välilyönnit. Välilyönnit eivät kuitenkaan vaikuta tuloksiin:
$ ./newressu --single --lineno -x -s8 -w8 -l1000 --space| ./cstat
ctrl LF:1000, space:7000
chars 0:4006, 1:3882, 2:3965, 3:3955, 4:3879, 5:4093, 6:4029, 7:3915, 8:4062, 9:4095, a:4105, b:3991, c:4023, d:4018, e:4014, f:3968, total:64000
cdiff 0:-6, 1:118, 2:35, 3:45, 4:121, 5:-93, 6:-29, 7:85, 8:-62, 9:-95, a:-105, b:9, c:-23, d:-18, e:-14, f:32
cstats min:3879, max:4105, total:64000, count:16, average:4000, characters:64000, utf8first:0, utf8other:0, ascii:71000, ctrl:1000, entropy:3.999789
multiple1 singles:64000, twins:3953, triplets:234, quadruplets:11, total:68198
m1expect singles:64000, twins:4000, triplets:250, quadruplets:15, total:68265
m1diff singles:0, twins:47, triplets:16, quadruplets:4, total:67
multiple2 singles:56328, twins:3496, triplets:212, quadruplets:11, total:64000
m2expect singles:56250, twins:3515, triplets:219, quadruplets:13, total:63989
m2diff singles:-78, twins:19, triplets:7, quadruplets:2, total:-50
monobit 0:127926, 1:128074, total:256000
poker2 0:31778, 1:32004, 2:32366, 3:31852, total:128000
Jos ajosta puuttuu –lineno parametri, eli rivinumero tulostetaan, rivinumero kenttä vääristää raporttia, tässä esimerkiksi suuri nollien määrä. Lisäksi ctrl-riville tulevat rivinumeron ja satunnaismerkkien väliset välilyönnit:
./newressu --single -x -s8 -w8 -l1000| ./cstat
ctrl LF:1000, space:1000
chars 0:6103, 1:4307, 2:4289, 3:4325, 4:4235, 5:4329, 6:4237, 7:4327, 8:4362, 9:4276, a:3972, b:4115, c:3985, d:4019, e:4023, f:4096, total:69000
cdiff 0:-1791, 1:5, 2:23, 3:-13, 4:77, 5:-17, 6:75, 7:-15, 8:-50, 9:36, a:340, b:197, c:327, d:293, e:289, f:216
cstats min:3972, max:6103, total:69000, count:16, average:4312.500000, characters:69000, utf8first:0, utf8other:0, ascii:70000, ctrl:1000, entropy:3.991895
multiple1 singles:69000, twins:5364, triplets:405, quadruplets:39, quintuplets:3, total:74811
m1expect singles:69000, twins:4312, triplets:269, quadruplets:16, quintuplets:1, total:73598
m1diff singles:0, twins:-1052, triplets:-136, quadruplets:-23, quintuplets:-2, total:-1213
multiple2 singles:58677, twins:4593, triplets:330, quadruplets:33, quintuplets:3, total:69000
m2expect singles:60644, twins:3790, triplets:236, quadruplets:14, quintuplets:0, total:68988
m2diff singles:1967, twins:-803, triplets:-94, quadruplets:-19, quintuplets:-3, total:1048
monobit 0:142723, 1:133277, total:276000
poker2 0:37709, 1:34059, 2:33246, 3:32986, total:138000
Binääristen satunnaislukujen (-b) tilastossa entropy (tässä satunnaisbittiä per merkki) lähenee ykkostä: Lisäksi chars rivillä on vain ‘0’ ja ‘1’ ja count = 2. Satunnaismateriaali koostuu nollista ja ykkösistä.
./newressu --single -b -s8 -w8 -l10000 --lineno | ./cstat
ctrl LF:10000
chars 0:319983, 1:320017, total:640000
cdiff 0:17, 1:-17
cstats min:319983, max:320017, total:640000, count:2, average:320000, characters:640000, utf8first:0, utf8other:0, ascii:640000, ctrl:10000, entropy:1.000000
multiple1 singles:640000, twins:319593, triplets:159651, quadruplets:79760, quintuplets:39885, sixlets:19962, 7lets:10030, 8lets:5021, 9lets:2520, 10lets:1300, 11lets:669, 12lets:340, 13lets:167, 14lets:76, 15lets:37, 16lets:14, 17lets:3, 18lets:1, total:1279029
m1expect singles:640000, twins:320000, triplets:160000, quadruplets:80000, quintuplets:40000, sixlets:20000, 7lets:10000, 8lets:5000, 9lets:2500, 10lets:1250, 11lets:625, 12lets:312, 13lets:156, 14lets:78, 15lets:39, 16lets:19, 17lets:9, 18lets:4, 19lets:2, 20lets:1, total:1279995
m1diff singles:0, twins:407, triplets:349, quadruplets:240, quintuplets:115, sixlets:38, 7lets:-30, 8lets:-21, 9lets:-20, 10lets:-50, 11lets:-44, 12lets:-28, 13lets:-11, 14lets:2, 15lets:2, 16lets:5, 17lets:6, 18lets:3, 19lets:2, 20lets:1, total:966
multiple2 singles:160465, twins:80051, triplets:40016, quadruplets:19952, quintuplets:9991, sixlets:4923, 7lets:2508, 8lets:1281, 9lets:589, 10lets:302, 11lets:156, 12lets:82, 13lets:52, 14lets:16, 15lets:12, 16lets:9, 17lets:1, 18lets:1, total:640000
m2expect singles:160000, twins:80000, triplets:40000, quadruplets:20000, quintuplets:10000, sixlets:5000, 7lets:2500, 8lets:1250, 9lets:625, 10lets:312, 11lets:156, 12lets:78, 13lets:39, 14lets:19, 15lets:9, 16lets:4, 17lets:2, 18lets:1, total:639921
m2diff singles:-465, twins:-51, triplets:-16, quadruplets:48, quintuplets:9, sixlets:77, 7lets:-8, 8lets:-31, 9lets:36, 10lets:10, 11lets:0, 12lets:-4, 13lets:-13, 14lets:3, 15lets:-3, 16lets:-5, 17lets:1, 18lets:0, total:-412
Oktaalisten satunnaislukujen entropy lähenee kolmosta: tietenkin chars rivillä on numerot ‘0’:sta ‘7’:aan ja count on 8. Materiaali koostuu merkeistä ‘0’:sta ‘7’:ään.
$ ./newressu --single -o -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:7997975, 1:8000644, 2:7998781, 3:7998010, 4:8005153, 5:7997054, 6:8002654, 7:7999729, total:64000000
cdiff 0:2025, 1:-644, 2:1219, 3:1990, 4:-5153, 5:2946, 6:-2654, 7:271
cstats min:7997054, max:8005153, total:64000000, count:8, average:8000000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:3.000000
multiple1 singles:64000000, twins:7999189, triplets:998260, quadruplets:124870, quintuplets:15650, sixlets:2015, 7lets:239, 8lets:41, 9lets:8, 10lets:2, total:73140274
m1expect singles:64000000, twins:8000000, triplets:1000000, quadruplets:125000, quintuplets:15625, sixlets:1953, 7lets:244, 8lets:30, 9lets:3, 10lets:0, total:73142855
m1diff singles:0, twins:811, triplets:1740, quadruplets:130, quintuplets:-25, sixlets:-62, 7lets:5, 8lets:-11, 9lets:-5, 10lets:-2, total:2581
multiple2 singles:48999882, twins:6127539, triplets:764170, quadruplets:95585, quintuplets:11859, sixlets:1578, 7lets:165, 8lets:27, 9lets:4, 10lets:2, total:64000000
m2expect singles:49000000, twins:6125000, triplets:765625, quadruplets:95703, quintuplets:11962, sixlets:1495, 7lets:186, 8lets:23, 9lets:2, 10lets:0, total:63999971
m2diff singles:118, twins:-2539, triplets:1455, quadruplets:118, quintuplets:103, sixlets:-83, 7lets:21, 8lets:-4, 9lets:-2, 10lets:-2, total:-815
Desimaalilukujen entropy lähenee 3.321928:aa (desimaalimerkki koostuu biteistä 1, 2 ja 4 ja osa bitistä 8) ja chars rivin numerot ovat välillä 0-9:
$ ./newressu --single -d -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:6396007, 1:6400047, 2:6402915, 3:6401529, 4:6404519, 5:6397437, 6:6398466, 7:6397870, 8:6397703, 9:6403507, total:64000000
cdiff 0:3993, 1:-47, 2:-2915, 3:-1529, 4:-4519, 5:2563, 6:1534, 7:2130, 8:2297, 9:-3507
cstats min:6396007, max:6404519, total:64000000, count:10, average:6400000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:3.321928
multiple1 singles:64000000, twins:6404055, triplets:640874, quadruplets:64161, quintuplets:6447, sixlets:625, 7lets:54, 8lets:1, total:71116217
m1expect singles:64000000, twins:6400000, triplets:640000, quadruplets:64000, quintuplets:6400, sixlets:640, 7lets:64, 8lets:6, total:71111110
m1diff singles:0, twins:-4055, triplets:-874, quadruplets:-161, quintuplets:-47, sixlets:15, 7lets:10, 8lets:5, total:-5107
multiple2 singles:51832764, twins:5186468, triplets:518999, quadruplets:51892, quintuplets:5251, sixlets:518, 7lets:52, 8lets:1, total:64000000
m2expect singles:51840000, twins:5184000, triplets:518400, quadruplets:51840, quintuplets:5184, sixlets:518, 7lets:51, 8lets:5, total:63999985
m2diff singles:7236, twins:-2468, triplets:-599, quadruplets:-52, quintuplets:-67, sixlets:0, 7lets:-1, 8lets:4, total:4053
Vielä uudestaan heksadesimaali, jossa entropy lähenee nelosta ja chars rivillä ja materiaalissa on heksanumerot(ita) ‘0’ – ‘f’:
$ ./newressu --single -x -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:4002235, 1:4000771, 2:3999619, 3:4000456, 4:3995918, 5:4000856, 6:4003044, 7:3999699, 8:3998536, 9:4000183, a:4001238, b:3998398, c:4000312, d:4001384, e:3999341, f:3998010, total:64000000
cdiff 0:-2235, 1:-771, 2:381, 3:-456, 4:4082, 5:-856, 6:-3044, 7:301, 8:1464, 9:-183, a:-1238, b:1602, c:-312, d:-1384, e:659, f:1990
cstats min:3995918, max:4003044, total:64000000, count:16, average:4000000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:4.000000
multiple1 singles:64000000, twins:4001492, triplets:249591, quadruplets:15572, quintuplets:959, sixlets:62, 7lets:3, total:68267679
m1expect singles:64000000, twins:4000000, triplets:250000, quadruplets:15625, quintuplets:976, sixlets:61, 7lets:3, total:68266665
m1diff singles:0, twins:-1492, triplets:409, quadruplets:53, quintuplets:17, sixlets:-1, 7lets:0, total:-1014
multiple2 singles:56246607, twins:3517882, triplets:219406, quadruplets:13716, quintuplets:838, sixlets:56, 7lets:3, total:64000000
m2expect singles:56250000, twins:3515625, triplets:219726, quadruplets:13732, quintuplets:858, sixlets:53, 7lets:3, total:63999985
m2diff singles:3393, twins:-2257, triplets:320, quadruplets:16, quintuplets:20, sixlets:-3, 7lets:0, total:1489
monobit 0:128004472, 1:127995528, total:256000000
poker2 0:32000082, 1:32002711, 2:32001597, 3:31995610, total:128000000
cstat sisältää –help parametrin, joka kertoo komennon kirjoitusasun: cstat tulostaa komennon kirjoitusasun myös, jos sen parametri on väärin kirjoitettu. Jos halutaan lukea stdin (oletus) tiedostoa, parametriksi voi laittaa pelkän miinusmerkin (‘-‘). Jos parametrin edellä ei ole miinusmerkkiä, se katsotaan tiedostoksi. Vain viimeinen tiedoston nimi katsotaan.
$ ./cstat --help
./cstat [-]/[filename] [--verbose] [--help] [--all] [--ctrl] [--chars] [--cdiff] [--cstats] [--multiple1] [--m1expect] [--m1diff] [--multiple2] [--m2expect] [--m2diff] [--monobit] [--poker2]
–verbose kytkimellä voit tulostaa sekä tilastot että datan samalle sivulle:
$ ./newressu --lineno| ./cstat --verbose
4351803043136516056288856573724573262070985983534430590448419963596642
3456174389372153988786921278046617965667514985321851793216687887157932
1902255648112995719416628601644736570744967017380038762966609076622811
1281509743204688618205185045706022024422762995194550322958445377790472
3784413827708402970490417813213564250017238858771981034500700507530704
9055168367119912878629899714626335171522022670864908592668742446542918
0191677706669306365217622375825024795059935366760530044265382851611997
3416723466929675866231727509034129352233311007024186331113208959024698
2335185850752231213099177908357629831877249743371602035678155510036859
7946039351097931583962995307389998234628068269367172182854699685499923
ctrl LF:10
chars 0:69, 1:69, 2:76, 3:70, 4:56, 5:70, 6:77, 7:73, 8:66, 9:74, total:700
cdiff 0:1, 1:1, 2:-6, 3:0, 4:14, 5:0, 6:-7, 7:-3, 8:4, 9:-4, total:0
cstats min:56, max:77, total:700, count:10, average:70, characters:700, utf8first:0, utf8other:0, ascii:700, ctrl:10, entropy:3.316983
multiple1 singles:700, twins:87, triplets:11, total:798
m1expect singles:700, twins:70, triplets:7, total:777
m1diff singles:0, twins:-17, triplets:-4, total:-21
multiple2 singles:537, twins:65, triplets:11, total:700
m2expect singles:567, twins:56, triplets:5, total:694
m2diff singles:30, twins:-9, triplets:-6, total:15
m2dist singles:1, twins:10, triplets:63, total:700
Oletuksena kaikki tulostettavat tilastorivit tulostetaan. –all kääntää kaikki rivit (ei tulosteta/tulostetaan). Jos haluat tulostaa pelkästään –chars rivin, se voidaan tehdä näin:
$ ./newressu --single -x -s8 -w8 -l1000 --lineno | ./cstat --all --chars
chars 0:4072, 1:3952, 2:3970, 3:4189, 4:4014, 5:3898, 6:4055, 7:3969, 8:3934, 9:4000, a:4089, b:3957, c:4013, d:3944, e:3971, f:3973, total:64000
Seuraavassa ajossa newressua ajetaan useita kertoja, ja tulostetaan raportti ensimmäisen merkin satunnaisuudesta:
$ cat newressuruns.sh
#!/bin/bash
echo "Statistics for first character on multiple runs of newressu: (./newressu --single --bin $@ -w1 -s1 --lineno -l1)"
rm -f newressuruns.rnd; for ((c=0;c<10000;c++)); do ./newressu --single --bin $@ -w1 -s1 --lineno -l1 >>newressuruns.rnd; done; cat newressuruns.rnd | ./newressutest7; rm -f newressuruns.rnd
$ ./newressuruns.sh
Statistics for first character on multiple runs of newressu: (./newressu --single --bin -w1 -s1 --lineno -l1)
ctrl LF:10000
chars 0:5046, 1:4954, total:10000, min:4954, max:5046
cdiff 0:-46, 1:46, total:0, min:-46, max:46
cstats min:4954, max:5046, total:10000, count:2, average:5000, characters:10000, utf8first:0, utf8other:0, ascii:10000, ctrl:10000, entropy:0.999939
multiple1 singles:10000, twins:4950, triplets:2457, quadruplets:1236, quintuplets:608, sixlets:308, 7lets:150, 8lets:71, 9lets:36, 10lets:18, 11lets:7, 12lets:1, total:19842
m1expect singles:10000, twins:5000, triplets:2500, quadruplets:1250, quintuplets:625, sixlets:312, 7lets:156, 8lets:78, 9lets:39, 10lets:19, 11lets:9, 12lets:4, 13lets:2, 14lets:1, total:19995
m1diff singles:0, twins:50, triplets:43, quadruplets:14, quintuplets:17, sixlets:4, 7lets:6, 8lets:7, 9lets:3, 10lets:1, 11lets:2, 12lets:3, 13lets:2, 14lets:1, total:153, min:0, max:50
multiple2 singles:2557, twins:1272, triplets:593, quadruplets:328, quintuplets:142, sixlets:79, 7lets:44, 8lets:17, 9lets:7, 10lets:5, 11lets:5, 12lets:1, total:10000
m2expect singles:2500, twins:1250, triplets:625, quadruplets:312, quintuplets:156, sixlets:78, 7lets:39, 8lets:19, 9lets:9, 10lets:4, 11lets:2, 12lets:1, total:9951
m2diff singles:-57, twins:-22, triplets:32, quadruplets:-16, quintuplets:14, sixlets:-1, 7lets:-5, 8lets:2, 9lets:2, 10lets:-1, 11lets:-3, 12lets:0, total:-55, min:-57, max:32
m2dist singles:3, twins:7, triplets:16, quadruplets:30, quintuplets:70, sixlets:126, 7lets:227, 8lets:588, 9lets:1428, 10lets:2000, 11lets:2000, 12lets:10000, total:10000
$
Raportin rivit puhuvat sen puolesta että tilastot toteutuvat myös eri ajot ylittävissä raporteissa. Tässä raportti jakautuu puoliksi nolliin ja ykkösiin, ja se tietysti johtaa siihen että myös datan monikot ovat tilaston mukaisia. Jos meillä on datana nolla, todennäköisyys on 50% että sen perään tulee toinen nolla, ja kahden nollan perään tulee nolla 50% tapauksista. Ressuhan satunnaistaa koko puskurin ennen ensimmäisen merkin palauttamista.
Toinen ohjelma jonka kirjoitin: tässä ideana on etsiä satunnaisjonoista tuplia. Tuplien maksimipituuden ja määrän pitäisi korreloida tiedoston tietueiden määrän kanssa. Esimerkiksi 64 merkkiä pitkiä tuplia ei pitäisi tulla, niiden todennäköisyys on niin pieni. –stat kytkimellä on aloiteltu tilaston laskemista, se on kuitenkin kesken. Ohjelma on nimetty uudelleen newressutest11:ksi ja komentoriviparametrejä on muutettu selkeämmäksi. Toki ohjelman mallikomennot jatkussa tarvitsevat uudet parametrit.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
unsigned char *procname;
static unsigned char *programname = "newressutest11/newressutest version 0.3 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 210
#define BINSIZE 10 // bytes per line
#define LINESIZE 21 // BINSIZE * 2 + 1
#define LINES 10
#define BLOCKSIZE 1024
#define GENT_SIZE 128
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
extern int verbose;
#define INPUT_RESSU 0
#define INPUT_PSEUDORESSU 1
#define INPUT_FASTRESSU 2
#define INPUT_SINGLERESSU 3
#define INPUT_RDRAND 4
#define INPUT_RDSEED 5
#define INPUT_URANDOM 6
#define INPUT_RANDOM 7
#define USE_RDRAND 2
#define USE_RDSEED 2
static unsigned char urandomfilename[128] = "/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128] = "/dev/random";
#endif
static void readfile_xor(int size,
unsigned char *buffer,
unsigned char *filename)
{
int c, n, n2;
unsigned char temp[64];
FILE *fp1;
if((fp1 = fopen(filename, "rb")) != NULL) {
while(size != 0) {
n = (size < sizeof(temp)) ? size : sizeof(temp);
n2 = fread(temp, 1, n, fp1);
for(c = 0; c < n2; c++)
buffer[c] ^= temp[c];
size -= n2;
buffer += n2;
}
fclose(fp1);
}
}
int input = 0;
void ressu_genbytes(int size, unsigned char *buffer);
void pseudoressu_bytes(int size, unsigned char *buffer);
void ressu_genbytes_fast(int size, unsigned char *buffer);
void ressu_genbytes_single(int size, unsigned char *buffer);
#if defined INPUT_RDRAND || defined INPUT_RDSEED
#include "fort.h"
#endif
int ressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(gent), gent);
#ifdef SHA256
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_FASTRESSU) // ressu_fast
ressu_genbytes_fast(sizeof(gent), gent);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(gent), gent);
#ifdef INPUT_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef INPUT_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(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
else {
fprintf(stderr,"%s: mode '%d' not available\n",
procname, input);
exit(2);
}
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long ressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | ressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
#include <string.h>
#include <stdlib.h>
//#define KILO 1000
#define KILO 1024
int stat = 0;
#ifdef NOTUSED
void fprintfdouble(FILE *fp1, unsigned char *text, double number)
{
int c;
unsigned char buffer[64];
sprintf(buffer,"%f", number);
// remove ending zeroes
for(c = strlen(buffer) - 1; c > 0 && buffer[c] == '0'; c--)
buffer[c] = '\0';
// remove ending dot
if(buffer[strlen(buffer) - 1] == '.')
buffer[strlen(buffer) - 1] = '\0';
fprintf(fp1, "%s", buffer);
fprintf(fp1, "%s", text);
}
#endif
#ifdef KOK
double fact(long n)
{
unsigned long l;
double result = 1;
for(l = 1; l <= n; l++) {
result = result * l;
}
return(result);
}
#endif
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// 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";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%lld%c", ll, units[c]);
}
#define DEBUG45 2
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u", base);
fprintf(stderr,", ll:%llu", prevll);
fprintf(stderr,", multiplier:%llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG45
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u", base);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x", final[c]);
}
}
#endif
#define DEBUG79 2
extern unsigned int fixedclockchainlength;
int clockmode; // 0 = normal, 1 = fixed
void ressu_setclock(int);
int main(int argc, char *argv[])
{
int c, percentageline = 1, prevpros, pros, quiet = 0;
int filesize_set = 0, binsize_set = 0, linesize_set = 0, lines_set = 0;
unsigned long long filesize = FILESIZE, lines = LINES;
unsigned int binsize = BINSIZE, linesize = LINESIZE;
unsigned long long plines = 0;
unsigned char *buffer, filename[128] = "";
FILE *fp1;
procname = argv[0];
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
percentageline = 0;
}
#ifdef KOK
long l, l2;
for(long l = 1; l < 10; l++) {
fprintf(stderr,"c:%ld", l);
l2 = fact(l);
fprintf(stderr,", result:%ld", l2);
fprintf(stderr,"\n");
}
#endif
for(c = 1; c < argc; c++) {
if(!strncmp("-", argv[c], 1)) {
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--linesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
linesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
linesize = getlonglong(argv[c + 1]);
c++;
}
linesize_set = 1;
} else if(!strncmp("--lines", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
lines = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
lines = getlonglong(argv[c + 1]);
c++;
}
lines_set = 1;
} else if(!strncmp("--binsize", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
binsize = getlonglong(argv[c] + 9);
} else if(c + 1 < argc) {
binsize = getlonglong(argv[c + 1]);
c++;
}
binsize_set = 1;
} else if(!strcmp("--stat", argv[c])) {
stat = !stat;
} else if(!strcmp("--verbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--quiet", argv[c])) {
quiet = !quiet;
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
} else if(!strcmp("--pseudoressu", argv[c])) {
input = INPUT_PSEUDORESSU;
} else if(!strcmp("--fast", argv[c])) {
input = INPUT_FASTRESSU;
} else if(!strcmp("--single", argv[c])) {
input = INPUT_SINGLERESSU;
#ifdef INPUT_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
#endif
#ifdef INPUT_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
#endif
} else if(!strcmp("--urandom", argv[c])) {
input = INPUT_URANDOM;
#ifdef USE_RANDOM
} else if(!strcmp("--random", argv[c])) {
input = INPUT_RANDOM;
#endif
} else if(!strncmp("--fixedclock", argv[c], 12)) {
if(*(argv[c] + 12)!='\0' && atoi(argv[c] + 12) > 1) {
fixedclockchainlength = atoi(argv[c] + 12);
clockmode = 1;
} else if(c + 1 < argc && atoi(argv[c + 1]) > 1) {
fixedclockchainlength = atoi(argv[c + 1]);
clockmode = 1;
c++;
} else {
clockmode = !clockmode;
}
if(fixedclockchainlength < 5 ||
fixedclockchainlength > 255)
fixedclockchainlength = 50;
ressu_setclock(clockmode);
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
}
if(!linesize_set)
linesize = binsize * 2 + 1;
else if(!binsize_set)
binsize = (linesize - 1) / 2;
if(!filesize_set)
filesize = lines * linesize;
else if(!lines_set) {
lines = (filesize + linesize - 1) / linesize; // round up
filesize = lines * linesize;
} else if(!linesize_set) {
linesize = (filesize + lines - 1) / lines; // round up
if((linesize & 1) == 0) // down to x * 2 + 1
linesize++;
binsize = (linesize - 1) / 2;
filesize = lines * linesize;
}
if(linesize != binsize * 2 + 1) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", linesize:%u", linesize);
fprintf(stderr,", binsize:%u", binsize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize != lines * linesize) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", lines:%llu", lines);
fprintf(stderr,", linesize:%u", linesize);
fprintf(stderr,", filesize:%llu", filesize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG79
fprintf(stderr,"input:%d", input);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(filename[0] == '\0')
fprintf(stderr,"filename:-\n");
else
fprintf(stderr,"filename:%s\n", filename);
if(filename[0] == '\0') {
fp1 = stdout;
} else {
if((fp1 = fopen(filename, "w")) == NULL) {
fprintf(stderr,"%s: cannot open file '%s' for writing\n", procname, filename);
exit(1);
}
}
if(stat) {
}
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if((buffer = malloc(linesize + 1)) == NULL) { // '\0' too
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
memset(buffer, 0, linesize + 1);
int mbinlines = (1 * KILO * KILO) / linesize;
prevpros = -1;
// fill first hex string
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", (unsigned int)ressu_gen_limit(256));
buffer[linesize - 1] = '\n';
buffer[linesize] = '\0';
for(;;) {
// bug! this program produces fixed length records
// and for some reason records end up being variable
// length records when they reach my removable usb
// drive (exfat). I am hoping this is silly one.
// next if() checks record length, and prints stars for
// variable length records. Havent seen stars yet...
// seems that fflush(), sync() fixes the problem.
if(linesize != strlen(buffer)) {
fprintf(stderr,"*");
fflush(stderr);
}
#ifdef FILE_HASH
HashUpdate(&hash, buffer, linesize); // calculate hash
#endif
if(fwrite(buffer, 1, linesize, fp1) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
if(plines > 0 && plines % mbinlines == 0) { // fflush and sync (EXFAT)
fflush(stdout);
sync();
}
plines++;
if(plines >= lines)
break;
// remove first byte
memmove(buffer, buffer + 2, linesize - 1);
// add new last byte
sprintf(buffer + linesize - 3, "%02x", (unsigned int)ressu_gen_limit(256));
buffer[linesize - 1] = '\n';
buffer[linesize] = '\0';
if(percentageline) { // && !quiet) {
pros = (int)((double) plines / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
}
}
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
if(percentageline) { // && !quiet) {
fprintf(stderr,"\rdone:100.0%% \n");
}
fflush(stdout); // fflush and sync (EXFAT)
sync();
if(filename[0] != '\0')
fclose(fp1);
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n", hashstring);
fclose(fp1);
}
} // end of if(filename[0] != '\0'
fprintf(stderr,", sha256:%s\n", hashstring);
#endif
free(buffer);
return(0);
}
Ohjelma tulostaa seuraavanlaisen raportin: raportin voi kirjoittaa suurelle kovalevylle, sortata ja tulostaa “tuplatietueet” uniq –check-chars=x optiolla. Lisää -b toiminnolla riville tulostettavia heksamerkkejä, ja -l optiolla rivejä sopivasti: seuraavassa rivillä on 30 merkkiä ja rivejä on 30. Katso tulostettavan tiedoston koko input: riviltä. Tässä 1030 merkkiä eli ~1 kb.
$ ./newressutest -b30 -l30
input:0, lines:30(0x1e), bytes:30(0x1e), total:1830b(0Tb,0Gb,0Mb,1Kb)
a4721b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f9
721b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f938
1b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804
581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d8
1d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88a
93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad8
beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f
b37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4f
7b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc2
3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258
e11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4
1d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9
86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c901
064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b
4be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07
e32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e1
2c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114
14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4
ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e495
ecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d
ee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d69
00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947
b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1
4e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd
8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52
bfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca
a27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca66
7b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b
63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b0a
f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b0a36
$
$ ./newressutest
input:0, lines:10(0xa), bytes:16(0x10), total:330b(0Tb,0Gb,0Mb,0Kb)
c80275eea3c4485e51afafaef99ed554
0275eea3c4485e51afafaef99ed554b1
75eea3c4485e51afafaef99ed554b16f
eea3c4485e51afafaef99ed554b16fdc
a3c4485e51afafaef99ed554b16fdc12
c4485e51afafaef99ed554b16fdc12ec
485e51afafaef99ed554b16fdc12ecda
5e51afafaef99ed554b16fdc12ecda9f
51afafaef99ed554b16fdc12ecda9f3d
afafaef99ed554b16fdc12ecda9f3d3e
Pieni bugivälike: Edellinen ohjelma tuottaa kiinteän mittaisia tietueita, mutta jostain syystä tietueen pituudet vaihtelevat neljä teraisella usb levylläni. Siksi tietueen pituuden tarkistava iffi edellisessä ohjelmassa. Mielestäni ongelman ei pitäisi olla ohjelmassa.
Pituuden tarkistusohjelma, joilla yritin etsiä ongelmapaikkaa. Tässä ohjelma, jolla voi tarkistaa inputin tietueiden pituudet:
#include <stdio.h>
#include <string.h>
#define BUFLEN 1024
void main(int argc, unsigned char *argv[])
{
unsigned long count;
unsigned char buffer[BUFLEN];
unsigned int inputlen = -1;
count = 0;
while(fgets(buffer, BUFLEN, stdin)) {
if(inputlen == -1) {
inputlen = strlen(buffer);
fprintf(stdout,"line length: %d\n",inputlen);
fflush(stdout);
} else if(inputlen != strlen(buffer)) {
fprintf(stdout," %lu",count);
}
count += strlen(buffer);
}
fprintf(stdout,"\n");
fflush(stdout);
}
Esimerkkejä tarkistusohjelman ajosta: ensimmäinen esimerkki
$ ./newressutest --pseudoressu -b20 -l1000 | ./newressutest6
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
line length: 41
Toinen esimerkki, joka tarkastaa sortin:
$ ./newressutest --pseudoressu -b20 -l1000 | sort | ./newressutest6
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
line length: 41
Kolmas. jossa tarkistetaan tehty tiedosto:
$ ./newressutest --pseudoressu -b20 -l1000 | sort > newressutest.deb
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
$ cat newressutest.deb | ./newressutest6
line length: 41
Bugilisäke jatkuu: Yksi löytämäni bugikohta:
365827042:d717d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82\
e556be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3\
b94a38f3bc80e1fc97da6571
365827043:17d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82e5\
56be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3b9\
4a38f3bc80e1fc97da65712f
365827044:d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82e556\
be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3b94a\
38f3bc80e1fc97da65712fd2
365848983:8e4431f3089c25af75df2677b0f511e1a690be147c4e01d766825d0220701b2a796cf75a13ae23a483cb1477968bca63ba43d2d3f8e555d\
a7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff8
365848984:d5103f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f4371\
46981e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f77\
92c55bb3d25f0f8f334ff898
365848985:103f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f437146\
981e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792\
c55bb3d25f0f8f334ff89859
365848986:3f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f43714698\
1e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792c5\
5bb3d25f0f8f334ff89859fa
Vielä esimerkki tuplaohjelman ajosta: voit esimerkiksi kasvatella rivimäärää -l1000 kytkimen numeroa kasvattamalla, ja tulostettavien tuplien pituutta –check-chars=6 numeroa kasvattamalla. Varmistathan että -b32 on riittävän suuri, Tässä on löytynyt 2 tuplaa, 07-alkuinen ja 19-alkuinen. Tietenkin tuplat ovat 6 merkin pituisia. Maksimituplien pituuden ja määrän pitäisi korreloida rivimäärän kanssa. Tässä haittana on että satunnaisrivit eivät jää talteen, eli niille ei voi tehdä jatkotutkimusta (esimerkiksi ajaa useampia uniq:ita samalle materiaalille). Voit tarkistaa myös että rivin lopussa (raportoidun tuplan jälkeen) ei ole liikaa lisää samanlaisia merkkejä, liian pitkä tupla olisi ongelma.
$ ./newressutest -b32 -l10000 | sort | uniq -D --check-chars=6
input:0, lines:10000(0x2710), bytes:32(0x20), total:650000b(0Tb,0Gb,0Mb,650Kb)
0764007efc362b5ddeaee81fe76561cae82728f988a70d3938eab5cc41b0e590
076400c3ad198728dc05d74862dbe2380696efc580f1f809c3eafa4c333d9ff5
1919f52e36204b0f2cb49ecd5a59b756fcb020db2c7dbf6d87005e8232c86f37
1919f5f0e0f85884ea321fb0692989e02a281e0bec91201d5e062f10c2f3bf2d
Tässä on ajettu newressutest11:sta exfat levyllä. Tässä versiossa on jo fflush ja sync kutsut. 256 gigainen tiedosto on ajettu onnistuneesti. Ajossa löytyi 4 tuplaa 32, 55, 77 ja 97 alkuiset. Kaikki tuplat ovat 16 pitkiä, eikä niissä ole samoja merkkejö 16 merkin jälkeen.
media$ ./newressutest11 --single --filesize256g | sort -T./temp/ | uniq -D --check-chars=16
string:'256g', base:10, multiplier:1073741824, prevll:256, ll:274877906944, totll:274877906944
input:3, lines:13089424141(~12G), binsize:10(10B), linesize:21(21B), filesize:274877906961(~256G)
filename:-
done:100.0%
./newressutest11: hashed file, sha256:f459507a66824e6e83b98d044c49bb39243bb320fb475158d9a6acedb8e34bcd
32630a8e6ddcc9406ba7
32630a8e6ddcc940be5d
5548db9879bbd10c5499
5548db9879bbd10c62c2
777432efb42ea3a89ca3
777432efb42ea3a8ce06
971fd08fa651e6980065
971fd08fa651e6985c9c
media$
Kolmas ohjelma tulostaa raportin, josta voi vertailla monikkojen eri merkkien esiintymistä. Chars rivi on kuten ennenkin yksittäisten eri merkkien esiintymät yhteensä. Chars rivillä on myös keskiarvo kokonaislukuna. Diff(eillä) rivillä on ero tilastolliseen määrään. m1digits singles rivillä on yksösten määrät (erikseen ‘0’, ‘1’, … ‘f’) tällä tulosteella (–hex). Vastaavasti m1digdiff rivillä on erot tilastoon. Erojen pitäisi olla sekä positiivisia että negatiivisia suhteellisen pieniä arvoja. dexp kentässä on odotettu määrä. Twins, triplets, quadruplets ja quintuplets rivejä luetaan samalla tavalla kun singles rivejä. Multiple1, m1exp, m1diff, multiple2, m2exp ja m2diff rivit ovat samankaltaisia kun edellisellä tulosteella.
$ ./newressu --lineno --space --hex -l10000 | ./newressutest8
ctrl LF:10000, space:130000
chars 0:35215, 1:34828, 2:34811, 3:34884, 4:34798, 5:35748, 6:35354, 7:34477, 8:35022, 9:34711, a:35015, b:34997, c:35401, d:34890, e:34756, f:35093, total:560000, count:16, average:35000, total:560000, min:34477, max:35748
cdiff 0:-215, 1:172, 2:189, 3:116, 4:202, 5:-748, 6:-354, 7:523, 8:-22, 9:289, a:-15, b:3, c:-401, d:110, e:244, f:-93, total:0, min:-748, max:523
multiple1 singles:560000, twins:35117, triplets:2606, quadruplets:328, quintuplets:39, sixlets:3, total:598093
m1exp singles:560000, twins:35000, triplets:2187, quadruplets:136, quintuplets:8, sixlets:0, total:597331
m1diff singles:0, twins:-117, triplets:-419, quadruplets:-192, quintuplets:-31, sixlets:-3, total:-762
m1digits singles 0:35215, 1:34828, 2:34811, 3:34884, 4:34798, 5:35748, 6:35354, 7:34477, 8:35022, 9:34711, a:35015, b:34997, c:35401, d:34890, e:34756, f:35093, dexp:35000, total:560000, texp:560000, min:34477, max:35748
m1digdiff singles 0:-215, 1:172, 2:189, 3:116, 4:202, 5:-748, 6:-354, 7:523, 8:-22, 9:289, a:-15, b:3, c:-401, d:110, e:244, f:-93, total:0, min:-748, max:523
m1digits twins 0:2219, 1:2285, 2:2248, 3:2223, 4:2128, 5:2185, 6:2244, 7:2049, 8:2216, 9:2263, a:2142, b:2137, c:2233, d:2226, e:2189, f:2130, dexp:2187, total:35117, texp:35000, min:2049, max:2285
m1digdiff twins 0:-32, 1:-98, 2:-61, 3:-36, 4:59, 5:2, 6:-57, 7:138, 8:-29, 9:-76, a:45, b:50, c:-46, d:-39, e:-2, f:57, total:-125, min:-98, max:138
m1digits triplets 0:167, 1:178, 2:180, 3:163, 4:128, 5:154, 6:153, 7:160, 8:161, 9:170, a:136, b:162, c:173, d:182, e:192, f:147, dexp:136, total:2606, texp:2187, min:128, max:192
m1digdiff triplets 0:-31, 1:-42, 2:-44, 3:-27, 4:8, 5:-18, 6:-17, 7:-24, 8:-25, 9:-34, a:0, b:-26, c:-37, d:-46, e:-56, f:-11, total:-430, min:-56, max:8
m1digits quadruplets 0:24, 1:27, 2:27, 3:21, 4:10, 5:13, 6:22, 7:19, 8:21, 9:17, a:20, b:15, c:23, d:24, e:29, f:16, dexp:8, total:328, texp:136, min:10, max:29
m1digdiff quadruplets 0:-16, 1:-19, 2:-19, 3:-13, 4:-2, 5:-5, 6:-14, 7:-11, 8:-13, 9:-9, a:-12, b:-7, c:-15, d:-16, e:-21, f:-8, total:-200, min:-21, max:-2
m1digits quintuplets 0:6, 1:3, 2:2, 3:2, 4:1, 6:4, 7:3, 8:3, a:4, c:3, d:2, e:5, f:1, dexp:0, total:39, texp:8, min:1, max:6
m1digdiff quintuplets 0:-6, 1:-3, 2:-2, 3:-2, 4:-1, 6:-4, 7:-3, 8:-3, a:-4, c:-3, d:-2, e:-5, f:-1, total:-39, min:-6, max:-1
m1digits sixlets 0:1, a:1, e:1, dexp:0, total:3, texp:0, min:1, max:1
m1digdiff sixlets 0:-1, a:-1, e:-1, total:-3, min:-1, max:-1
multiple2 singles:492372, twins:30233, triplets:1989, quadruplets:253, quintuplets:33, sixlets:3, total:560000
m2exp singles:492187, twins:30761, triplets:1922, quadruplets:120, quintuplets:7, sixlets:0, total:559990
m2diff singles:-185, twins:528, triplets:-67, quadruplets:-133, quintuplets:-26, sixlets:-3, total:-10
m2digits singles 0:30944, 1:30436, 2:30495, 3:30601, 4:30670, 5:31532, 6:31019, 7:30539, 8:30751, 9:30355, a:30867, b:30885, c:31108, d:30620, e:30570, f:30980, dexp:30761, total:492372, texp:492187, min:30355, max:31532
m2digdiff singles 0:-183, 1:325, 2:266, 3:160, 4:91, 5:-771, 6:-258, 7:222, 8:10, 9:406, a:-106, b:-124, c:-347, d:141, e:191, f:-219, total:-196, min:-771, max:406
m2digits twins 0:1909, 1:1956, 2:1915, 3:1918, 4:1882, 5:1890, 6:1960, 7:1748, 8:1915, 9:1940, a:1890, b:1828, c:1910, d:1886, e:1834, f:1852, dexp:1922, total:30233, texp:30761, min:1748, max:1960
m2digdiff twins 0:13, 1:-34, 2:7, 3:4, 4:40, 5:32, 6:-38, 7:174, 8:7, 9:-18, a:32, b:94, c:12, d:36, e:88, f:70, total:519, min:-38, max:174
m2digits triplets 0:125, 1:127, 2:128, 3:123, 4:109, 5:128, 6:113, 7:125, 8:122, 9:136, a:100, b:132, c:130, d:136, e:139, f:116, dexp:120, total:1989, texp:1922, min:100, max:139
m2digdiff triplets 0:-5, 1:-7, 2:-8, 3:-3, 4:11, 5:-8, 6:7, 7:-5, 8:-2, 9:-16, a:20, b:-12, c:-10, d:-16, e:-19, f:4, total:-69, min:-19, max:20
m2digits quadruplets 0:13, 1:21, 2:23, 3:17, 4:8, 5:13, 6:14, 7:13, 8:15, 9:17, a:13, b:15, c:17, d:20, e:20, f:14, dexp:7, total:253, texp:120, min:8, max:23
m2digdiff quadruplets 0:-6, 1:-14, 2:-16, 3:-10, 4:-1, 5:-6, 6:-7, 7:-6, 8:-8, 9:-10, a:-6, b:-8, c:-10, d:-13, e:-13, f:-7, total:-141, min:-16, max:-1
m2digits quintuplets 0:4, 1:3, 2:2, 3:2, 4:1, 6:4, 7:3, 8:3, a:2, c:3, d:2, e:3, f:1, dexp:0, total:33, texp:7, min:1, max:4
m2digdiff quintuplets 0:-4, 1:-3, 2:-2, 3:-2, 4:-1, 6:-4, 7:-3, 8:-3, a:-2, c:-3, d:-2, e:-3, f:-1, total:-33, min:-4, max:-1
m2digits sixlets 0:1, a:1, e:1, dexp:0, total:3, texp:0, min:1, max:1
m2digdiff sixlets 0:-1, a:-1, e:-1, total:-3, min:-1, max:-1
$
Tässä vielä bash:iin perustuva näkemys tuplista: (en ole varma näkyvätkö tuplat jossain selaimessa, minulla ne näkyvät bashissa punaisella)
$./newressu | grep "00\|11\|22\|33\|44\|55\|66\|77\|88\|99"
00000 50601770965858790287746351436604015693184573567799066517653601656
00001 48694546975015201968596666905183123871308274139328912966079898679
00002 79811004632452834690694925920237574068709382185064173509186665896
00003 67948756258916859329418821550901897658164278464642949542074825264
00004 33624858011285146428020109871734597275263223498277932780645159687
00005 17971792316063297502277999536969560242964320788109401452364923409
00006 35291566680695002181737688811100316149439988651827176360642157605
00007 11370134868289458957910751111498131857275527242659407122148439815
00008 26708050136430661831450323981723744901224836837055153985157327353
00009 26529141654263551049396906874524955288851596692074733373992155155
$
Vielä ohjelma:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "newressutest8 version 0.2 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
void fprintfmultipletype(FILE *fp1, int c)
{
switch(c) {
case 0: fprintf(fp1, "singles"); break;
case 1: fprintf(fp1, "twins"); break;
case 2: fprintf(fp1, "triplets"); break;
case 3: fprintf(fp1, "quadruplets"); break;
case 4: fprintf(fp1, "quintuplets"); break;
case 5: fprintf(fp1, "sixlets"); break;
default: fprintf(fp1, "%dlets", c + 1); break;
}
}
int main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1,
ctrl = 1, chars = 1, cdiff = 1,
multiple1 = 1, m1exp = 1, m1diff = 1,
m1digits = 1, m1digdiff = 1,
multiple2 = 1, m2exp = 1, m2diff = 1,
m2digits = 1, m2digdiff = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
multiple1 = all;
m1exp = all;
m1diff = all;
m1digits = all;
m1digdiff = all;
multiple2 = all;
m2exp = all;
m2diff = all;
m2digits = all;
m2digdiff = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--m1", argv[c])) {
multiple1 = !multiple1;
m1exp = !m1exp;
m1diff = !m1diff;
m1digits = !m1digits;
m1digdiff = !m1digdiff;
} else if(!strcmp("--m1dig", argv[c])) {
m1digits = !m1digits;
m1digdiff = !m1digdiff;
} else if(!strcmp("--multiple1", argv[c])) {
multiple1 = !multiple1;
} else if(!strcmp("--m1exp", argv[c])) {
m1exp = !m1exp;
} else if(!strcmp("--m1diff", argv[c])) {
m1diff = !m1diff;
} else if(!strcmp("--m1digits", argv[c])) {
m1digits = !m1digits;
} else if(!strcmp("--m1digdiff", argv[c])) {
m1digdiff = !m1digdiff;
} else if(!strcmp("--m2", argv[c])) {
multiple2 = !multiple2;
m2exp = !m2exp;
m2diff = !m2diff;
m2digits = !m2digits;
m2digdiff = !m2digdiff;
} else if(!strcmp("--m2dig", argv[c])) {
m2digits = !m2digits;
m2digdiff = !m2digdiff;
} else if(!strcmp("--multiple2", argv[c])) {
multiple2 = !multiple2;
} else if(!strcmp("--m2exp", argv[c])) {
m2exp = !m2exp;
} else if(!strcmp("--m2diff", argv[c])) {
m2diff = !m2diff;
} else if(!strcmp("--m2digits", argv[c])) {
m2digits = !m2digits;
} else if(!strcmp("--m2digdiff", argv[c])) {
m2digdiff = !m2digdiff;
} else {
fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
#ifdef DEBUG17
fprintf(stdout,"multiple1:%d", multiple1);
fprintf(stdout,", m1exp:%d", m1exp);
fprintf(stdout,", m1diff:%d", m1diff);
fprintf(stdout,"\n");
#endif
// print help message if needed
if(help) {
fprintf(stderr,"%s",procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--multiple1]");
fprintf(stderr," [--m1exp]");
fprintf(stderr," [--m1diff]");
fprintf(stderr," [--m1digits]");
fprintf(stderr," [--m1digdiff]");
fprintf(stderr," [--multiple2]");
fprintf(stderr," [--m2exp]");
fprintf(stderr," [--m2diff]");
fprintf(stderr," [--m2digits]");
fprintf(stderr," [--m2digdiff]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename,"-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
int currentchar = 0;
unsigned char prevchars[MAX];
unsigned long int m1counts[MAX];
unsigned long int m2counts[MAX];
for(c = 0; c < MAX; c++) {
prevchars[c] = 0;
m1counts[c] = 0;
m2counts[c] = 0;
}
unsigned long int singles = 0;
int ch, prevch;
unsigned long m2length;
first = 1;
unsigned char buffer[1024];
unsigned char *ifile = NULL;
unsigned long long ifilelength = 0;
// read input file to buffer
while(fgets(buffer,sizeof(buffer),fp1)!=NULL) {
if(verbose) {
fprintf(stdout,"%s",buffer);
}
int bytes = 0;
if(ifile != NULL)
bytes += strlen(ifile);
bytes += strlen(buffer);
bytes += 1;
if(ifilelength < bytes) {
ifilelength = bytes;
if((ifile = realloc(ifile, ifilelength)) == NULL) {
fprintf(stderr,"%s:",procname);
fprintf(stderr," realloc(): cannot allocate memory");
fprintf(stderr,", %lld bytes",ifilelength);
fprintf(stderr,"\n");
exit(2);
}
}
strcat(ifile, buffer);
}
if(verbose)
fflush(stdout);
unsigned char *p;
p = ifile;
while((ch = *p++) != '\0') {
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) // ctrl or space, skip
continue;
singles++;
} // end of for(c = 0; c < ifilelength; c++)
if(singles == 0) {
fprintf(stderr,"%s: no data\n", procname);
exit(2);
}
int charnum[MAXCOUNT];
int charascii[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++) {
charnum[c] = -1;
charascii[c] = -1;
}
int num = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20) // ctrl or space, skip
continue;
if(charcounts[c] != 0) {
charnum[c] = num;
charascii[num] = c;
num++;
}
}
#define aDEBUG25 2
#ifdef DEBUG25
fprintf(stdout,"charnum ");
for(c = 0; c < MAXCOUNT; c++) {
if(charnum[c] != -1)
fprintf(stdout," %d:%d", c, charnum[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
fprintf(stdout,"charascii");
for(c = 0; c < MAXCOUNT; c++) {
if(charascii[c] != -1)
fprintf(stdout," %d:%d", c, charascii[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
#endif
unsigned long int count = 0, ctotal = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c <= 0x20) // ctrl or space, skip
continue;
ctotal += charcounts[c];
count++;
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
long m1multiplecounts[MAX][count];
long m2multiplecounts[MAX][count];
for(c = 0; c < MAX; c++) {
for(d = 0; d < count; d++) {
m1multiplecounts[c][d] = 0;
m2multiplecounts[c][d] = 0;
}
}
p = ifile;
first = 1;
m2length = 0;
while((ch = *p++) != '\0') {
if(ch <= 0x20) // ctrl or space, skip
continue;
// calculate m1 multiple
// counts
prevchars[currentchar] = ch;
for(c = 0; c < MAX; c++) {
d = currentchar - c;
if(d < 0)
d += MAX;
if(ch != prevchars[d])
break;
m1counts[c]++;
m1multiplecounts[c][charnum[ch]]++;
}
if(++currentchar >= MAX)
currentchar -= MAX;
// calculate m2 multiple
// counts
if(first) {
prevch = ch;
m2length = 1;
first = 0;
} else {
if(prevch == ch) {
m2length++;
} else {
m2counts[m2length - 1]++;
m2multiplecounts[m2length - 1][charnum[prevch]]++;
m2length = 1;
prevch = ch;
}
}
} // end of for(c = 0; c < ifilelength; c++)
if(m2length > 0) {
m2counts[m2length - 1]++; // add last m2 multiple
m2multiplecounts[m2length - 1][charnum[prevch]]++;
}
#ifdef DEBUG46
for(c = 0; c < MAX; c++) {
for(d = 0; d < count; d++) {
fprintf(stdout," %lu",m2multiplecounts[c][d]);
}
fprintf(stdout,"\n");
}
#endif
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
}
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(ctrl)
// calculate average
unsigned long int average;
average = ctotal / count;
long int min;
long int max;
min = LONG_MAX;
max = LONG_MIN;
// print character counts if needed
if(chars) {
long int allchars;
fprintf(stdout,"chars ");
first = 1;
allchars = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%lu", charcounts[c]);
allchars += charcounts[c];
if(min > charcounts[c])
min = charcounts[c];
if(max < charcounts[c])
max = charcounts[c];
first = 0;
}
}
fprintf(stdout,", total:%ld", allchars);
fprintf(stdout,", count:%ld", count);
fprintf(stdout,", average:%ld", average);
fprintf(stdout,", total:%ld", allchars);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(chars)
// calculate and print character
// differences
min = LONG_MAX;
max = LONG_MIN;
if(cdiff) {
fprintf(stdout,"cdiff ");
long int chardiff = 0;
long int chardifftotal = 0;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%ld", average - charcounts[c]);
chardiff = (average - charcounts[c]);
chardifftotal += chardiff;
if(min > chardiff)
min = chardiff;
if(max < chardiff)
max = chardiff;
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,", total:%ld", chardifftotal);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cdiff)
// print statistics on m1 multiples,
// multiple1, m1exp and m1diff
for(int e = 0; e < 3; e++) {
if(e==0) {
if(!multiple1)
continue;
fprintf(stdout, "multiple1 ");
} else if(e==1) {
if(!m1exp)
continue;
fprintf(stdout, "m1exp ");
} else {
if(!m1diff)
continue;
fprintf(stdout, "m1diff ");
}
long int total = 0;
long int expect = singles;
first = 1;
for(c = 0; c < MAX; c++) {
if(m1counts[c] > 0) {
if(!first)
fprintf(stdout,", ");
fprintfmultipletype(stdout, c);
long int temp;
if(e == 0)
temp = m1counts[c];
else if(e == 1)
temp = expect;
else
temp = expect - m1counts[c];
total += temp;
fprintf(stdout,":%ld", temp);
}
expect /= count;
first = 0;
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of for(int e = 0; e < 3; e++)
// print statistics on m1 multiples,
// m1digits and m1digdiff
long int m1expected = singles;
for(c = 0; c < MAX; c++) {
int print = 0;
for(d = 0; d < count; d++) {
if(m1multiplecounts[c][d] != 0)
print = 1;
}
if(print) {
for(int e = 0; e < 2; e++) { // 0 -> digits, 1 -> diff
if(e==0) {
if(!m1digits)
continue;
fprintf(stdout,"m1digits ");
} else if(e==1) {
if(!m1digdiff)
continue;
fprintf(stdout,"m1digdiff ");
}
min = LONG_MAX;
max = LONG_MIN;
fprintfmultipletype(stdout, c);
unsigned long total = 0;
first = 1;
for(d = 0; d < count; d++) {
if(m1multiplecounts[c][d] != 0) {
unsigned char ch = charascii[d];
if(!first)
fprintf(stdout,",");
fprintf(stdout," ");
if(isprint(ch) && ch > ' ')
fprintf(stdout,"%c", ch);
else
fprintf(stdout,"%02x", ch);
long temp;
if(e == 0)
temp = m1multiplecounts[c][d];
else if(e == 1)
temp = m1expected / count - m1multiplecounts[c][d];
fprintf(stdout,":%ld", temp);
total += temp;
first = 0;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
}
}
if(!first) {
if(e == 0)
fprintf(stdout,", dexp:%ld", m1expected / count);
fprintf(stdout,", total:%ld", total);
if(e == 0)
fprintf(stdout,", texp:%ld", m1expected);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
}
fprintf(stdout,"\n");
} // end of for(int e = 0; e < 2; e++)
}
m1expected /= count;
}
unsigned long int m2expects[MAX];
double base;
for(c = 0; c < MAX; c++) {
m2expects[c] = 0;
}
base = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
if(base * ctotal > 0) {
m2expects[c] = (unsigned long int) (base * ctotal);
base *= ((double)1 / count);
}
}
// print statistics on m2 multiples
// multiple1 m2exp and m2diff
for(int e = 0; e < 3; e++) {
if(e==0) {
if(!multiple2)
continue;
fprintf(stdout,"multiple2 ");
} else if(e==1) {
if(!m2exp)
continue;
fprintf(stdout,"m2exp ");
} else {
if(!m2diff)
continue;
fprintf(stdout,"m2diff ");
}
unsigned long int total = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
fprintfmultipletype(stdout, c);
long int temp;
if(e == 0) {
temp = m2counts[c];
//total += temp * (c + 1);
} else if(e == 1) {
temp = m2expects[c];
//total += temp * (c + 1);
} else {
temp = m2expects[c] - m2counts[c];
//total += temp;
}
fprintf(stdout,":%ld", temp);
total += temp * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%ld",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end if for(int e = 0; e < 3; e++)
// print statistics on m2 multiples
// m2digits and m2digdiff
double m2expectedbase = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
int print = 0;
for(d = 0; d < count; d++) {
if(m2multiplecounts[c][d] != 0)
print = 1;
}
if(print) {
unsigned long m2exp = m2expectedbase * ctotal;
for(int e = 0; e < 2; e++) { // 0 -> digits, 1 -> diff
if(e==0) {
if(!m2digits)
continue;
fprintf(stdout,"m2digits ");
} else {
if(!m2digdiff)
continue;
fprintf(stdout,"m2digdiff ");
}
min = LONG_MAX;
max = LONG_MIN;
fprintfmultipletype(stdout, c);
first = 1;
long int total = 0;
for(d = 0; d < count; d++) {
if(m2multiplecounts[c][d] != 0) {
unsigned char ch = charascii[d];
if(!first)
fprintf(stdout,",");
fprintf(stdout," ");
if(isprint(ch) && ch > ' ')
fprintf(stdout,"%c", ch);
else
fprintf(stdout,"%02x", ch);
long temp;
if(e==0)
temp = m2multiplecounts[c][d];
else
temp = m2exp / count - m2multiplecounts[c][d];
fprintf(stdout,":%ld", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
}
if(!first) {
if(e == 0)
fprintf(stdout,", dexp:%lu", (unsigned long) m2exp / count);
fprintf(stdout,", total:%ld", total);
if(e == 0)
fprintf(stdout,", texp:%lu", (unsigned long) m2exp);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
}
fprintf(stdout,"\n");
} // end of for(int e = 0; e < 2; e++)
m2expectedbase *= ((double)1 / count);
}
}
}
Neljäs ohjelma jonka kirjoitin tekee edelleen tilastoja satunnaisuudesta: tällä kertaa tilastoidaan newressu tulosteen sanoja (words), eli välilyönneillä eroteltuja satunnaismerkkisarjoja. Seuraavassa raportissa sanan pituus on 1, jolloin tuotettu raportti on vastaa aiemmin laskettua chars riviä. Tällä voi debukata words toimintoa. Raportin –set toiminnolla voidaan tulostaa tietue, johon words rakenne lasketaan (vrt terttu).
$ ./newressu --bin -s1 --lineno --space -l1000| ./newressutest9 --set
set '0' = "18112", '1' = "17888"
ctrl LF:1000, space:35000
chars 0:18112, 1:17888, words:2, total:36000, average:18000, min:17888, max:18112
cdiff 0:-112, 1:112, total:0, min:-112, max:112
words 0:18112, 1:17888, words:2, total:36000, average:18000, min:17888, max:18112
wdiff 0:-112, 1:112, total:0, min:-112, max:112
$
Varsinainen toiminta on kuitenkin siinä että verrataan useampimerkkisiä sanoja:
$ ./newressu --bin -s2 --lineno --space -l1000 | ./newressutest9 --set
set '00' = "6061", '01' = "5916", '10' = "6009", '11' = "6014"
ctrl LF:1000, space:23000
chars 0:24047, 1:23953, words:2, total:48000, average:24000, min:23953, max:24047
cdiff 0:-47, 1:47, total:0, min:-47, max:47
words 00:6061, 01:5916, 10:6009, 11:6014, words:4, total:24000, average:6000, min:5916, max:6061
wdiff 00:-61, 01:84, 10:-9, 11:-14, total:0, min:-61, max:84
$
Edellisessä on listattu binääriset 2 bittiset sanat, jotka ovat 00, 01, 10 ja 11. Koska vaihtoehtoja on neljä, yhden yhdistelmän todennäköisyys on 1/4 eli 25%.
Listaan poikkeuksellisesti ensimmäisenä newressutest9:n tietorakenteen hallinnan, koska se on tavallaan erillinen kokonaisuus. En kuitenkaan vielä laittanut sitä omaan tiedostoon:
unsigned char *db5_set = NULL;
unsigned char *db5_get_set()
{
return(db5_set);
}
void db5_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
void db5_get_element(unsigned int *namelen, unsigned char **name, unsigned int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db5_skipwhite(&p);
if(*p == '\'') { // name
p++;
*name = p;
*namelen = 0;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
}
db5_skipwhite(&p);
if(*p == '=') {
p++;
}
db5_skipwhite(&p);
if(*p == '\"') { // value
p++;
*value = p;
*valuelen = 0;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
}
db5_skipwhite(&p);
*p2 = p;
}
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
int db5_get(unsigned char *name, int valuesize, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen = strlen(name);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** get\n");
#endif
value[0] = '\0';
if(db5_set != NULL) {
firstelement = 1;
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = strlen(value);
break;
}
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(db5_set != NULL)
return(retval);
}
#define SORTED 2
void db5_put(unsigned char *name, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
unsigned int namelen = strlen(name);
unsigned int valuelen = strlen(value);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** put\n");
#endif
firstelement = 1;
lastelement = 0;
if(db5_set != NULL) {
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 &&
!strncmp(name, name2, namelen) ) {
found = 1;
thiselement = currentelement;
nextelement = p; // beginning of next element
break;
}
#ifdef SORTED
// we reached greater name
if(namelen == namelen2 &&
strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
thiselement = currentelement;
nextelement = currentelement;
break;
} else {
// common beginning of strings
int comblen = namelen;
if(comblen > namelen2)
comblen = namelen2;
int cmp = strncmp(name, name2, comblen);
if((cmp < 0) || // first characters less (aaaa, b)
(!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
thiselement = currentelement;
nextelement = currentelement;
break;
}
}
#endif
if(*p == '\0')
lastelement = 1;
firstelement = 0;
} // end of while(*p != '\0')
} else { // else of if(db5_set != NULL)
lastelement = 1;
firstelement = 1;
} // end of if(db5_set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%s' = \"%s\""; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%s' = \"%s\", "; // --> comma in the end (first new)
else
elementfmt = ", '%s' = \"%s\""; // ..> comma in the beginning (other)
// print element
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
if(elementsize < count) {
elementsize = count;
if((element = realloc(element, elementsize)) == NULL) {
fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
}
#ifdef DEBUG22
fprintf(stdout,", set: %s", db5_set);
fprintf(stdout,"\n");
#endif
// calculate change in length
long oldcount = 0;
count = 0;
if(db5_set != NULL) {
count += strlen(db5_set);
oldcount = count + 1; // + '\0'
}
if(found) // change in value only
count += valuelen - valuelen2; // no punctuation marks
else
count += strlen(element);
count++; // + '\0'
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout, "old length:%ld %s\n", oldcount, db5_set);
fflush(stdout);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempdb5_set = db5_set;
if((db5_set = realloc(db5_set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = db5_set + (thiselement - tempdb5_set);
if(nextelement != NULL)
nextelement = db5_set + (nextelement - tempdb5_set);
if(tempdb5_set == NULL)
db5_set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = db5_set + strlen(db5_set);
if(nextelement == NULL)
nextelement = db5_set + strlen(db5_set);
// move end of the set
memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too
// add new element
memmove(thiselement, element, strlen(element));
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout,"new length:%ld %s\n", count, db5_set);
fflush(stdout);
}
#endif
#ifdef DEBUG10
fprintf(stdout,", set %s(%ld)", db5_set, strlen(db5_set));
fprintf(stdout,"\n");
fflush(stdout);
#endif
}
Edellinen koodi listaa db5_put():in db5_get():in, joilla voisi olla potentiaalia myös tertun ytimeen.
Seuraavassa lista, josta näkee selvemmin datarakenteen:
$ cat newressudb5test.sh
#!/bin/bash
for ((c=0;c<5;c++)); do ./newressu --single --bin -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --oct -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --dec -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --hex -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
$ ./newressudb5test.sh
set '0' = "17983", '1' = "18017"
set '0' = "17935", '1' = "18065"
set '0' = "17851", '1' = "18149"
set '0' = "18034", '1' = "17966"
set '0' = "18086", '1' = "17914"
set '0' = "4507", '1' = "4508", '2' = "4524", '3' = "4466", '4' = "4438", '5' = "4542", '6' = "4538", '7' = "4477"
set '0' = "4535", '1' = "4541", '2' = "4467", '3' = "4589", '4' = "4449", '5' = "4510", '6' = "4390", '7' = "4519"
set '0' = "4528", '1' = "4502", '2' = "4445", '3' = "4507", '4' = "4574", '5' = "4444", '6' = "4516", '7' = "4484"
set '0' = "4442", '1' = "4493", '2' = "4505", '3' = "4394", '4' = "4600", '5' = "4531", '6' = "4494", '7' = "4541"
set '0' = "4569", '1' = "4346", '2' = "4472", '3' = "4464", '4' = "4447", '5' = "4585", '6' = "4551", '7' = "4566"
set '0' = "3572", '1' = "3571", '2' = "3573", '3' = "3633", '4' = "3596", '5' = "3616", '6' = "3743", '7' = "3492", '8' = "3622", '9' = "3582"
set '0' = "3620", '1' = "3650", '2' = "3567", '3' = "3610", '4' = "3561", '5' = "3622", '6' = "3698", '7' = "3556", '8' = "3553", '9' = "3563"
set '0' = "3598", '1' = "3616", '2' = "3594", '3' = "3732", '4' = "3587", '5' = "3603", '6' = "3511", '7' = "3598", '8' = "3562", '9' = "3599"
set '0' = "3577", '1' = "3575", '2' = "3640", '3' = "3568", '4' = "3648", '5' = "3591", '6' = "3570", '7' = "3577", '8' = "3682", '9' = "3572"
set '0' = "3584", '1' = "3643", '2' = "3621", '3' = "3696", '4' = "3522", '5' = "3698", '6' = "3526", '7' = "3611", '8' = "3630", '9' = "3469"
set '0' = "2344", '1' = "2323", '2' = "2156", '3' = "2296", '4' = "2314", '5' = "2249", '6' = "2275", '7' = "2220", '8' = "2289", '9' = "2202", 'a' = "2227", 'b' = "2262", 'c' = "2240", 'd' = "2177", 'e' = "2211", 'f' = "2215"
set '0' = "2235", '1' = "2151", '2' = "2361", '3' = "2218", '4' = "2214", '5' = "2218", '6' = "2266", '7' = "2251", '8' = "2281", '9' = "2192", 'a' = "2227", 'b' = "2313", 'c' = "2259", 'd' = "2236", 'e' = "2337", 'f' = "2241"
set '0' = "2209", '1' = "2197", '2' = "2289", '3' = "2343", '4' = "2260", '5' = "2253", '6' = "2298", '7' = "2195", '8' = "2224", '9' = "2197", 'a' = "2205", 'b' = "2308", 'c' = "2254", 'd' = "2221", 'e' = "2266", 'f' = "2281"
set '0' = "2234", '1' = "2270", '2' = "2310", '3' = "2151", '4' = "2271", '5' = "2259", '6' = "2295", '7' = "2199", '8' = "2318", '9' = "2207", 'a' = "2230", 'b' = "2206", 'c' = "2275", 'd' = "2275", 'e' = "2253", 'f' = "2247"
set '0' = "2314", '1' = "2290", '2' = "2202", '3' = "2300", '4' = "2133", '5' = "2218", '6' = "2229", '7' = "2292", '8' = "2208", '9' = "2251", 'a' = "2224", 'b' = "2239", 'c' = "2289", 'd' = "2248", 'e' = "2279", 'f' = "2284"
$
Listan alussa on laskettu binääri merkkejä (5 riviä), seuraavaksi oktaalimerkkejä, desimaalimerkkejä ja heksamerkkejä.
Datarakenteessa on tässä sanat (words) ja samanlaisten sanojen lukumäärä, mutta kun sanan tilalle laittaa kentän nimen ja lukumäärän tilalle kentän arvon, voidaan alkaa miettimään esimerkiksi appia tilaus ja siihen liittyviä kenttia ja tiedostoja (tilaus, asiakas, tilausrivit, tuote, asiakasmyynti, toimitus jne.). Edit: Tietenkin ilman kovakoodattuja sarakkeita, tauluja ja appeja.
Ja koodi kokonaisuudessaan: (huomaa että ohjelmassa on TEST80 kappale, joka ristiintarkistaa chars rivin ja words rivin luvut, se on nyt päällä)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "newressutest9 version 0.3 ©";
static unsigned char *copyright = "Copyright (c) 1998-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
unsigned char *db5_set = NULL;
unsigned char *db5_get_set()
{
return(db5_set);
}
void db5_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
void db5_get_element(unsigned int *namelen, unsigned char **name, unsigned int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db5_skipwhite(&p);
if(*p == '\'') { // name
p++;
*name = p;
*namelen = 0;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
}
db5_skipwhite(&p);
if(*p == '=') {
p++;
}
db5_skipwhite(&p);
if(*p == '\"') { // value
p++;
*value = p;
*valuelen = 0;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
}
db5_skipwhite(&p);
*p2 = p;
}
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
int db5_get(unsigned char *name, int valuesize, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen = strlen(name);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** get\n");
#endif
value[0] = '\0';
if(db5_set != NULL) {
firstelement = 1;
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = strlen(value);
break;
}
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(db5_set != NULL)
return(retval);
}
#define SORTED 2
void db5_put(unsigned char *name, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
unsigned int namelen = strlen(name);
unsigned int valuelen = strlen(value);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** put\n");
#endif
firstelement = 1;
lastelement = 0;
if(db5_set != NULL) {
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 &&
!strncmp(name, name2, namelen) ) {
found = 1;
thiselement = currentelement;
nextelement = p; // beginning of next element
break;
}
#ifdef SORTED
// we reached greater name
if(namelen == namelen2 &&
strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
thiselement = currentelement;
nextelement = currentelement;
break;
} else {
// common beginning of strings
int comblen = namelen;
if(comblen > namelen2)
comblen = namelen2;
int cmp = strncmp(name, name2, comblen);
if((cmp < 0) || // first characters less (aaaa, b)
(!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
thiselement = currentelement;
nextelement = currentelement;
break;
}
}
#endif
if(*p == '\0')
lastelement = 1;
firstelement = 0;
} // end of while(*p != '\0')
} else { // else of if(db5_set != NULL)
lastelement = 1;
firstelement = 1;
} // end of if(db5_set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%s' = \"%s\""; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%s' = \"%s\", "; // --> comma in the end (first new)
else
elementfmt = ", '%s' = \"%s\""; // ..> comma in the beginning (other)
// print element
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
if(elementsize < count) {
elementsize = count;
if((element = realloc(element, elementsize)) == NULL) {
fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
}
#ifdef DEBUG22
fprintf(stdout,", set: %s", db5_set);
fprintf(stdout,"\n");
#endif
// calculate change in length
long oldcount = 0;
count = 0;
if(db5_set != NULL) {
count += strlen(db5_set);
oldcount = count + 1; // + '\0'
}
if(found) // change in value only
count += valuelen - valuelen2; // no punctuation marks
else
count += strlen(element);
count++; // + '\0'
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout, "old length:%ld %s\n", oldcount, db5_set);
fflush(stdout);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempdb5_set = db5_set;
if((db5_set = realloc(db5_set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = db5_set + (thiselement - tempdb5_set);
if(nextelement != NULL)
nextelement = db5_set + (nextelement - tempdb5_set);
if(tempdb5_set == NULL)
db5_set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = db5_set + strlen(db5_set);
if(nextelement == NULL)
nextelement = db5_set + strlen(db5_set);
// move end of the set
memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too
// add new element
memmove(thiselement, element, strlen(element));
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout,"new length:%ld %s\n", count, db5_set);
fflush(stdout);
}
#endif
#ifdef DEBUG10
fprintf(stdout,", set %s(%ld)", db5_set, strlen(db5_set));
fprintf(stdout,"\n");
fflush(stdout);
#endif
}
void increment(unsigned char *name)
{
int count = 0;
unsigned char buffer[32];
#ifdef DEBUG9
fprintf(stdout, "********** increment\n");
#endif
if(db5_get(name, sizeof(buffer), buffer) != 0)
count = atoi(buffer);
count++;
sprintf(buffer,"%d", count);
db5_put(name, buffer);
}
void main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1, set = 0,
ctrl = 1, chars = 1, cdiff = 1,
words = 1, wdiff = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
#define aTEST39 2 // default is off
#ifdef TEST39
// tests for earlier db5 routines
db5_set = "'kala' = \"kele\", 'kala2' = \"kele2\", 'kala3' = \"kele3\"";
unsigned int valuelen = 1024, valuelen2;
unsigned char value[1024];
// dbget
fprintf(stdout,"db5\n");
fflush(stdout);
db5_get("kala", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
db5_get("kala2", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
db5_get("kala3", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
// dbput and sorting
db5_set = NULL;
db5_put("kala", "kele");
db5_put("kala1", "kele1");
db5_put("kala2", "kele2");
db5_put("kala21", "kele211111");
db5_put("kala3", "kele3");
db5_put("kala2", "kele2b");
db5_put("kala21", "kele21");
db5_put("kala21", "kele21111");
// test increment
free(db5_set);
db5_set = NULL;
increment("a");
increment("b");
increment("b");
increment("c");
increment("c");
increment("c");
// utf8 characters
free(db5_set);
db5_set = NULL;
increment("⚀");
increment("⚁");
increment("⚂");
increment("⚃");
increment("⚄");
increment("⚅");
// sorting with different lengths of name
free(db5_set);
db5_set = NULL;
db5_put("ccccc", "ccccc");
db5_put("a", "a");
db5_put("bbbb", "bbbb");
db5_put("b", "b");
db5_put("cccc", "cccc");
db5_put("c", "c");
db5_put("aaaaa", "aaaaa");
db5_put("aa", "aa");
db5_put("bb", "bb");
db5_put("aaa", "aaa");
db5_put("bbbbb", "bbbbb");
db5_put("cc", "cc");
db5_put("aaaaa", "aaaaa");
db5_put("aaaa", "aaaa");
db5_put("bbb", "bbb");
db5_put("ccc", "ccc");
fprintf(stdout,"db5_set:%s\n", db5_set);
free(db5_set);
db5_set = NULL;
//exit(1);
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--set", argv[c])) { // display db5_set
set = !set;
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
words = all;
wdiff = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--words", argv[c])) {
words = !words;
} else if(!strcmp("--wdiff", argv[c])) {
wdiff = !wdiff;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--words]");
fprintf(stderr," [--wdiff]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename, "-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
int currentchar = 0;
unsigned long int singles = 0;
int ch, prevch;
first = 1;
unsigned char buffer[1024];
unsigned char *ifile = NULL; // input file
unsigned long long ifilelength = 0;
// read input file to buffer
while(fgets(buffer, sizeof(buffer), fp1) != NULL) {
if(verbose) {
fprintf(stdout,"%s", buffer);
}
int bytes = 0;
if(ifile != NULL)
bytes += strlen(ifile);
bytes += strlen(buffer);
bytes += 1;
if(ifilelength < bytes) {
unsigned char *tempifile = ifile;
ifilelength = bytes;
if((ifile = realloc(ifile, ifilelength)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(2);
}
if(tempifile == NULL)
ifile[0] = '\0';
}
strcat(ifile, buffer);
}
if(verbose)
fflush(stdout);
unsigned char *p;
p = ifile;
while((ch = *p++) != '\0') {
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) { // ctrl or space, skip
continue;
}
singles++;
} // end of for(c = 0; c < ifilelength; c++)
if(singles == 0) {
fprintf(stderr,"%s: no data\n",procname);
exit(2);
}
int wcount = 0; // word count
p = ifile;
while(*p != '\0') {
while(*p <= 0x20 && *p != '\0')
p++;
int count = 0;
unsigned char *w, word[128];
// get word
w = word;
while(*p > 0x20 && *p != '\0') {
if(++count < sizeof(word))
*w++ = *p;
p++;
}
*w = '\0';
if(count > 0) {
increment(word);
wcount++;
}
} // end of while(*p != '\0')
if(set) {
fprintf(stdout,"set %s\n", db5_set);
fflush(stdout);
}
unsigned long int count = 0, ctotal = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c <= 0x20) // ctrl or space, skip
continue;
ctotal += charcounts[c];
count++;
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(ctrl)
unsigned long int caverage;
// calculate average for character statistics
caverage = ctotal / count;
long int min;
long int max;
// print character statistics
for(int e = 0; e < 2; e++) {
long int total = 0;
min = LONG_MAX;
max = LONG_MIN;
if(e == 0) {
if(!chars)
continue;
fprintf(stdout,"chars ");
} else {
if(!cdiff)
continue;
fprintf(stdout,"cdiff ");
}
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
long int temp;
if(e == 0)
temp = charcounts[c];
else
temp = caverage - charcounts[c];
fprintf(stdout,":%ld", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
} // end of if(charcounts[c] > 0)
if(e == 0) {
fprintf(stdout,", words:%ld", count);
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", average:%ld", caverage);
} else {
fprintf(stdout,", total:%ld", total);
}
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of for(int e = 0; e < 2: e++)
unsigned char *iset = db5_get_set();
unsigned int namelen, valuelen;
unsigned char *name, *value;
#define TEST80 2 // default on (for now)
#ifdef TEST80
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
long int tcount = 0;
p = iset;
while(*p != '\0') {
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
long int temp;
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
temp = atol(tempbuffer);
for(d = 0; d < namelen; d++) {
if(name[d] == c)
tcount += temp;
}
} // end of while(*p != '\0')
#define aDEBUG84 2
#ifdef DEBUG84
if(charcounts[c] != 0 || tcount != 0) {
fprintf(stderr,"%s: test", procname);
fprintf(stderr,", c:%d", c);
fprintf(stderr,", charcount:%ld", charcounts[c]);
fprintf(stderr,", tcount:%ld\n", tcount);
}
#endif
if(charcounts[c] != tcount) {
fprintf(stderr,"%s: internal error:", procname);
fprintf(stderr,"wordcounts and charcounts do not match");
fprintf(stderr,", char:%c(0x%02x)", c, c);
fprintf(stderr,", charcount:%ld", charcounts[c]);
fprintf(stderr,", tcount:%ld", tcount);
fprintf(stderr,"\n");
//exit(2);
}
} // for(c = 0; c < MAXCOUNT; c++)
#endif
unsigned long wtotal = 0;
unsigned long wordscnt = 0;
// calculate words statistics average
// first words total and count
p = iset;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
long int temp;
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
temp = atol(tempbuffer);
wtotal += temp;
wordscnt++;
} // end of while(*set != '\0')
// average (words statistics)
long int waverage = wtotal / wordscnt;
// print words statistics
for(int e = 0; e < 2; e++) {
unsigned long total = 0;
min = LONG_MAX;
max = LONG_MIN;
if(e == 0) {
if(!words)
continue;
fprintf(stdout,"words ");
} else {
if(!wdiff)
continue;
fprintf(stdout,"wdiff ");
}
unsigned char *iset = db5_get_set();
// read thru elements element by element
first = 1;
p = iset;
while(*p != '\0') {
if(!first)
fprintf(stdout, ", ");
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
long int temp;
if(e == 0)
temp = atol(tempbuffer);
else
temp = waverage - atol(tempbuffer);
fprintf(stdout,"%.*s:", namelen, name);
fprintf(stdout,"%ld", temp);
if(min > temp)
min = temp;
if(max < temp)
max = temp;
total += temp;
first = 0;
} // end of while(*set != '\0')
if(e == 0) {
fprintf(stdout,", words:%ld", wordscnt);
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", average:%ld", waverage);
} else {
fprintf(stdout,", total:%ld", total);
}
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} //end of for(e = 0;e < 2; e++)
}
Tässä vielä kuva DEBUG11:n tulostamasta listasta: Listalle tulee kaksi riviä (old ja new) silloin kun set:n koko muuttuu, eli käydään muuttamassa tietueen kokoa realloc:issa.
$ ./newressu --dec --space --lineno -s1 -l10 | ./newressutest9 --set | more
old length:0 (null)
new length:10 '9' = "1"
old length:10 '9' = "1"
new length:21 '0' = "1", '9' = "1"
old length:21 '0' = "1", '9' = "1"
new length:32 '0' = "1", '7' = "1", '9' = "1"
old length:32 '0' = "1", '7' = "1", '9' = "1"
new length:43 '0' = "1", '2' = "1", '7' = "1", '9' = "1"
old length:43 '0' = "1", '2' = "1", '7' = "1", '9' = "1"
new length:54 '0' = "1", '2' = "1", '4' = "1", '7' = "1", '9' = "1"
old length:54 '0' = "1", '2' = "1", '4' = "1", '7' = "1", '9' = "1"
new length:65 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '7' = "1", '9' = "1"
old length:65 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '7' = "1", '9' = "1"
new length:76 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "1", '9' = "1"
old length:76 '0' = "2", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "2", '9' = "1"
new length:87 '0' = "2", '1' = "1", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "2", '9' = "1"
old length:87 '0' = "5", '1' = "3", '2' = "1", '3' = "2", '4' = "1", '5' = "7", '7' = "3", '9' = "4"
new length:98 '0' = "5", '1' = "3", '2' = "1", '3' = "2", '4' = "1", '5' = "7", '7' = "3", '8' = "1", '9' = "4"
old length:98 '0' = "5", '1' = "5", '2' = "1", '3' = "3", '4' = "5", '5' = "9", '7' = "3", '8' = "3", '9' = "5"
new length:109 '0' = "5", '1' = "5", '2' = "1", '3' = "3", '4' = "5", '5' = "9", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
old length:109 '0' = "5", '1' = "5", '2' = "1", '3' = "4", '4' = "5", '5' = "9", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
new length:110 '0' = "5", '1' = "5", '2' = "1", '3' = "4", '4' = "5", '5' = "10", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
old length:110 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "9", '9' = "6"
new length:111 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
old length:111 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
new length:112 '0' = "8", '1' = "10", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
old length:112 '0' = "9", '1' = "15", '2' = "4", '3' = "6", '4' = "6", '5' = "15", '6' = "5", '7' = "5", '8' = "14", '9' = "6"
new length:113 '0' = "10", '1' = "15", '2' = "4", '3' = "6", '4' = "6", '5' = "15", '6' = "5", '7' = "5", '8' = "14", '9' = "6"
old length:113 '0' = "11", '1' = "20", '2' = "6", '3' = "9", '4' = "8", '5' = "16", '6' = "6", '7' = "8", '8' = "17", '9' = "6"
new length:114 '0' = "11", '1' = "20", '2' = "6", '3' = "10", '4' = "8", '5' = "16", '6' = "6", '7' = "8", '8' = "17", '9' = "6"
old length:114 '0' = "13", '1' = "20", '2' = "6", '3' = "10", '4' = "9", '5' = "17", '6' = "8", '7' = "8", '8' = "18", '9' = "7"
new length:115 '0' = "13", '1' = "20", '2' = "6", '3' = "10", '4' = "10", '5' = "17", '6' = "8", '7' = "8", '8' = "18", '9' = "7"
old length:115 '0' = "13", '1' = "20", '2' = "7", '3' = "11", '4' = "11", '5' = "21", '6' = "8", '7' = "9", '8' = "19", '9' = "8"
new length:116 '0' = "13", '1' = "20", '2' = "7", '3' = "11", '4' = "11", '5' = "21", '6' = "8", '7' = "10", '8' = "19", '9' = "8"
old length:116 '0' = "15", '1' = "22", '2' = "7", '3' = "11", '4' = "12", '5' = "21", '6' = "9", '7' = "10", '8' = "19", '9' = "9"
new length:117 '0' = "15", '1' = "22", '2' = "7", '3' = "11", '4' = "12", '5' = "21", '6' = "9", '7' = "10", '8' = "19", '9' = "10"
old length:117 '0' = "15", '1' = "22", '2' = "8", '3' = "11", '4' = "12", '5' = "22", '6' = "9", '7' = "10", '8' = "20", '9' = "10"
new length:118 '0' = "15", '1' = "22", '2' = "8", '3' = "11", '4' = "12", '5' = "22", '6' = "10", '7' = "10", '8' = "20", '9' = "10"
old length:118 '0' = "20", '1' = "25", '2' = "9", '3' = "14", '4' = "14", '5' = "25", '6' = "14", '7' = "15", '8' = "23", '9' = "11"
new length:119 '0' = "20", '1' = "25", '2' = "10", '3' = "14", '4' = "14", '5' = "25", '6' = "14", '7' = "15", '8' = "23", '9' = "11"
set '0' = "36", '1' = "43", '2' = "26", '3' = "28", '4' = "35", '5' = "44", '6' = "31", '7' = "40", '8' = "47", '9' = "30"
ctrl LF:10, space:350
chars 0:36, 1:43, 2:26, 3:28, 4:35, 5:44, 6:31, 7:40, 8:47, 9:30, words:10, total:360, average:36, min:26, max:47
cdiff 0:0, 1:-7, 2:10, 3:8, 4:1, 5:-8, 6:5, 7:-4, 8:-11, 9:6, total:0, min:-11, max:10
words 0:36, 1:43, 2:26, 3:28, 4:35, 5:44, 6:31, 7:40, 8:47, 9:30, words:10, total:360, average:36, min:26, max:47
wdiff 0:0, 1:-7, 2:10, 3:8, 4:1, 5:-8, 6:5, 7:-4, 8:-11, 9:6, total:0, min:-11, max:10
$
Uudelleenkirjoitin myös newressun stat_line rutiinit: uudessa versiossa ideana on että tilarivi tulostetaan vain, jos se on muuttunut. Uudessa versiossa tilarivi kootaan stat_line muuttujaan ja end() rutiinissa koko rivi tulostetaan, jos se on muuttunut. End() rutiini tallettaa stat_line muuttujan prev_stat_line muuttujaan seuraavaa vertailua varten. cursor_remove() ja cursor_start() kutsut on siirretty _end() rutiiniin.
static int cursor_on = 0;
unsigned char cursor[4] = { '|', '/', '-', '\\' };
long int prev_secs = -1;
int crs = 0;
void stat_line_cursor_start()
{
fprintf(stderr, " ");
fflush(stderr);
prev_secs = -1;
cursor_on = 1;
}
void stat_line_cursor()
{
long int secs;
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;
}
}
void stat_line_cursor_remove()
{
if(cursor_on) {
fprintf(stderr, "\b \b");
fflush(stderr);
prev_secs = -1;
}
cursor_on = 0;
}
#include <stdarg.h>
#define aDEBUG31 2
unsigned char *procname = NULL;
static unsigned char *prev_stat_line = NULL;
static unsigned char *stat_line = NULL;
static size_t stat_line_length = 0;
static void stat_line_begin()
{
if(stat_line != NULL)
stat_line[0] = '\0';
}
static void stat_line_printf(const unsigned char *format, ...)
{
int count;
va_list args;
static unsigned char *buffer = NULL;
static size_t buffer_length = 0;
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
if(buffer_length < count) {
buffer_length = count;
buffer = realloc(buffer, buffer_length);
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
}
count = 0;
if(stat_line != NULL)
count += strlen(stat_line);
count += strlen(buffer);
count++;
if(stat_line_length < count) {
unsigned char *stat_line2 = stat_line;
stat_line_length = count;
stat_line = realloc(stat_line, stat_line_length);
prev_stat_line = realloc(prev_stat_line, stat_line_length);
if(stat_line2 == NULL) {
stat_line[0] = '\0';
prev_stat_line[0] = '\0';
}
}
strcat(stat_line, buffer);
}
#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_get_readable(unsigned char buf10[10], unsigned long length)
{
int c, low;
double length2;
// 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' ||
units[c] == 'M' ||
units[c] == 'G' ||
units[c] == 'T')
sprintf(buf10, "%.3f", length2);
else if(length == length2)
sprintf(buf10, "%ld", length);
else
sprintf(buf10, "%.1f", length2);
if(strchr(buf10, '.') != NULL) {
int d;
d = strlen(buf10) - 1;
while(d > 3 && isdigit(buf10[d])) {
buf10[d] = '\0';
d--;
}
if(buf10[strlen(buf10)-1] == '.')
buf10[strlen(buf10)-1] ='\0';
}
if(units[c] != 'B') {
char unit[10];
sprintf(unit,"%cB",units[c]);
strcat(buf10, unit);
}
break;
}
length2 = (double)length / READABLE_NUMBER_DIVIDER;
length /= READABLE_NUMBER_DIVIDER;
low = 1;
}
}
static void stat_line_readable(unsigned long length)
{
unsigned char buf10[10];
stat_line_get_readable(buf10, length);
stat_line_printf("%s", buf10);
}
void stat_line_end()
{
int c, d;
if(stat_line != NULL && strcmp(prev_stat_line, stat_line)) { // status line changed
stat_line_cursor_remove();
#ifdef DEBUG31
fprintf(stderr, "\n");
#else
fprintf(stderr, "\r");
#endif
fprintf(stderr,"%s", stat_line);
fflush(stderr);
// previous line longer than this one,
// overwrite with spaces and backspace to
// end
d = strlen(prev_stat_line) - strlen(stat_line) + 1; // cursor too
if(d > 0) { // previous line longer
for(c = 0; c < d; c++) {
#ifdef DEBUG31
fprintf(stderr, "*");
#else
fprintf(stderr, " "); // print spaces
#endif
}
#ifndef DEBUG31
for(c = 0; c < d; c++)
fprintf(stderr, "\b"); // and backspaces
#endif
}
strcpy(prev_stat_line, stat_line);
if(strlen(stat_line) > 0)
stat_line_cursor_start();
}
}
sample() rutiini eli tiedoston muodostaminen satunnaisbiteistä sai myös uudelleenkirjoitusta. Aiemmin koodissa oli kaikkia clim ja dlim muuttujia, uudessa versiossa on vain tiedoston pituus merkkeinä ja blokin koko. Lisäksi aiemmat cursor_remove ja cursor_start rutiinit on poistettu niiden stat_line rutiiniin lisäämisen takia. Tiedoston nimeen on lisätty sarjanumero, joten sample ei poista aiempia tuloksia. Pilkkujen käyttöä tilarivissä on muutettu. Dieharder-satunnaislukuanalyysin voi myös ajaa automaattisesti sample ajon jälkeen. (–dieharder komentorivitoiminto). Die tulee ilmeisesti sanasta noppa.. Sample rutiinissa on ajon aikainen tilarivi, siinä on esimerkki aiempien rutiinien käytöstä.
static int sample = 0, dieharder = 0; // randomness analysis
// try randomness analysis with: $ dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t oldhandler;
void sample_handler()
{
static int times = 0;
times++;
fprintf(stderr,"Ctrl-c pressed %d times\n", times);
if(times >= 10) {
signal(SIGINT, oldhandler);
exit(1);
}
}
#define KILO 1024
void dump_sample() // & dieharder analysis
{
//#define SAMPLE_FILESIZE 64 * 1024 * 1024 * 1024
#define SAMPLE_FILESIZE 1 * 1024 * 1024 * 1024
//#define SAMPLE_FILESIZE 1 * 512 * 1024 * 1024 * 1024
//#define SAMPLE_FILESIZE 8 * 1024 * 1024 * 1024 // 28 times
//#define SAMPLE_BLOCKSIZE 1024
#define STAT_LINE_BLOCK 2 // on by default
#define STAT_LINE_WRITTEN 2 // on by default
#define STAT_LINE_SPEED 2 // on by default
#define STAT_LINE_NOW 2 // on by default
#define STAT_LINE_LEFT 2 // on by default
#define STAT_LINE_READY 2 // on by default
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
unsigned long long c;
unsigned char buffer[SAMPLE_BLOCKSIZE], filename[128], command[1024];
FILE *fp1;
time_t secondsstart, secondsnow;
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, samplefilename, c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
unsigned char filename2[138];
sprintf(filename2,"%s.dieharder",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef SAMPLE_HASH
sprintf(filename2,"%s.sha256",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
// you have to press ctrl-c 10 times
oldhandler = signal(SIGINT, sample_handler);
#define DEBUG58 2 // default on (for now)
#ifdef DEBUG58
fprintf(stderr,"%s: sample: writing file", procname);
fprintf(stderr,", filename:%s", filename);
#ifndef SAMPLE_WRITE
fprintf(stderr,", no write");
#endif
fprintf(stderr,"\n");
#endif
#ifdef SAMPLE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // calculate hash
#endif
if((fp1 = fopen(filename, "a")) != NULL) {
secondsstart = time(NULL);
long long clim = (long long) SAMPLE_FILESIZE / (SAMPLE_BLOCKSIZE);
int mbinblocks = (1 * KILO * KILO) / SAMPLE_BLOCKSIZE;
for(c = 0; c < clim; c++) {
if(c % 256 == 0) {
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();
int print = 0;
#ifdef STAT_LINE_BLOCK
stat_line_printf("%s", randomgen[input]);
// print block from 0 to 8192
stat_line_printf("block %d", c / (clim / 8192));
print = 1;
#endif
#ifdef STAT_LINE_WRITTEN
// print written
if(print)
stat_line_printf(", ");
stat_line_printf("written ");
stat_line_readable((unsigned long)c * SAMPLE_BLOCKSIZE);
print = 1;
#endif
if(c > 0) {
#ifdef STAT_LINE_SPEED
// print speed
if(print)
stat_line_printf(", ");
if(secondsnow - secondsstart > 1.0)
stat_line_readable((unsigned long)((double)c * SAMPLE_BLOCKSIZE / (secondsnow - secondsstart)) );
else
stat_line_readable((unsigned long)((double)c * SAMPLE_BLOCKSIZE));
stat_line_printf("/sec");
print = 1;
#endif
#if defined STAT_LINE_NOW || \
defined STAT_LINE_READY
char timebuf[128];
#endif
#ifdef STAT_LINE_READY
char timebuf2[128];
#endif
#ifdef STAT_LINE_NOW
// print now
if(print)
stat_line_printf(", ");
stat_line_printf("now");
strftime(timebuf, sizeof(timebuf), TIMEFORMAT2,
localtime((time_t *)&secondsnow));
stat_line_printf(" %s", timebuf);
print = 1;
#endif
#ifdef STAT_LINE_LEFT
// print left
unsigned long int secondsleft = (int)((((double)secondsnow - secondsstart) / c) * (clim - c) );
unsigned long int secondsleft2;
unsigned long int temp;
int timeprinted = 0;
//int hoursprinted = 0;
if(print)
stat_line_printf(", ");
secondsleft2 = secondsleft;
stat_line_printf("left");
temp = secondsleft2 / (24 * 3600); // days
if(temp > 0) {
timeprinted = 1;
stat_line_printf(" %dd", temp);
secondsleft2 -= temp * (24 * 3600);
}
temp = secondsleft2 / 3600; // hours
if(temp > 0 || timeprinted) {
timeprinted = 1;
//hoursprinted = 1;
stat_line_printf(" %02dh", temp);
secondsleft2 -= temp * 3600;
}
temp = secondsleft2 / 60; // minutes
if(temp > 0 || timeprinted) {
timeprinted = 1;
stat_line_printf(" %02dm", temp);
secondsleft2 -= temp * 60;
}
temp = secondsleft2; // seconds
if(!timeprinted) {
stat_line_printf(" %d seconds", temp);
}
print = 1;
#endif
#ifdef STAT_LINE_READY
long int secondsend = (int)secondsstart + ((((double)secondsnow - secondsstart) / c) * clim);
// print end date if different
if(print)
stat_line_printf(", ");
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);
print = 1;
#endif
}
stat_line_end();
}
// do the work
stat_line_cursor();
memset(buffer, 0, sizeof(buffer));
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(buffer), buffer);
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(buffer), buffer);
else if(input == INPUT_FASTRESSU) // ressu fast
ressu_genbytes_fast(sizeof(buffer), buffer);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(buffer), buffer);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(sizeof(buffer), buffer);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(sizeof(buffer), buffer);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(buffer), buffer);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(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 USE_DUMMY
else if(input == INPUT_DUMMY) {
// no generator
}
#endif
else {
fprintf(stdout,"\n%s: mode '%d'(%s) not available\n",
procname, input, randomgen[input]);
exit(2);
}
#ifdef SAMPLE_HASH
HashUpdate(&hash, buffer, sizeof(buffer)); // calculate hash
#endif
#ifdef SAMPLE_WRITE
if(input != INPUT_DUMMY) {
fwrite(buffer, 1, sizeof(buffer), fp1);
#ifdef SAMPLE_SYNC
if(c % mbinblocks == 0) { // fflush and sync (EXFAT)
fflush(fp1);
sync();
}
#endif
} // end of if(input != INPUT_DUMMY
#endif
} // end of for(c = 0; c < clim; c++
#ifdef SAMPLE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fflush(fp1); // fflush and sync (EXFAT)
sync();
fclose(fp1);
} else { // if((fp1=fopen
fprintf(stderr,"%s:", procname);
fprintf(stderr," sample: cannot open file");
fprintf(stderr,", filename: %s", filename);
fprintf(stderr,"\n");
exit(2);
}
// remove last status line
stat_line_begin();
stat_line_printf("\rwrote ");
stat_line_readable((unsigned long)c * SAMPLE_BLOCKSIZE);
stat_line_printf(", ");
if(secondsnow - secondsstart >= 1.0)
stat_line_readable((unsigned long)((double)c * SAMPLE_BLOCKSIZE / (secondsnow - secondsstart)) );
else
stat_line_readable((unsigned long)c * SAMPLE_BLOCKSIZE);
stat_line_printf("/sec");
stat_line_printf(", done!");
stat_line_end();
fprintf(stdout,"\n");
fflush(stdout);
#ifdef SAMPLE_HASH
unsigned char filename2[138];
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,"%s: sample: hashing file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,", hashfilename:%s", filename2);
fprintf(stderr,", sha256:%s\n", hashstring);
if((fp1 = fopen(filename2, "a")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
fprintf(stderr,"%s: sample: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
sprintf(command,"sha256sum %s", filename);
system(command);
#endif
signal(SIGINT, oldhandler);
if(dieharder) { // randomness analysis
sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder", filename, filename);
fprintf(stderr,"%s: dieharder: running dieharder \"%s\"\n", procname, command);
system(command);
exit(0);
}
}
Seuraavassa ajetaan sample() ja –dieharder analyysi: Dieharder on antanut yleensä muutamia WEAK:keja:
$ ./newressu --single --sample --dieharder
./newressu: sample: writing file, filename:newressusample1.rnd
wrote 16.0GB, 4.1MB/sec, done!
./newressu: dieharder: running dieharder "dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder"
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 10 times
# The file file_input_raw was rewound 11 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 13 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
$ fgrep WEAK newressusample1.rnd.dieharder
rgb_lagged_sum| 18| 1000000| 100|0.99605238| WEAK
media$ fgrep FAILED newressusample1.rnd.dieharder
media$
Edellisessä ajossakin tuli pari heikosti suoriuduttua riviä.
Bugivälike: Tästä raportista tuli varsinainen bugiraportti, ensin ressussa löytyi tuo +2 ongelma, sitten ongelmia usb levyn kanssa (talletettu tiedosto ei ollut fixed length). Näistä +2 bugi sai korjauksen, joten jäljelle jäi usb ongelma. Kokeilin ajaa –sample –dieharderin usb levyllä, ja se meni läpi ihan ok: tällä kertaa yksi WEAK:ki. Huomaa myös että ajo on tehty –single moodilla..
media$ ./newressu --single --sample --dieharder
./newressu: sample: writing file, filename:newressusample1.rnd
wrote 16.0GB, 4.1MB/sec, done!
./newressu: dieharder: running dieharder "dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder"
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 10 times
# The file file_input_raw was rewound 11 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 13 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
media$ fgrep WEAK newressusample1.rnd.dieharder
rgb_lagged_sum| 18| 1000000| 100|0.99605238| WEAK
media$ fgrep FAILED newressusample1.rnd.dieharder
media$
.rnd tiedostossa oli myös oikea koko. Itse käytän usb levyjä koko ajan ja ajattelinkin ihmetellä sitä vielä hetken.. Sample():n tulos on tietysti jatkuva tiedosto, joten muutoksia siinä ei näe. Lisättyä tietoa ei ilmeisesti (koon perusteella) ole.
Kirjoitin uuden ohjelman levynkirjoitusongelmaa varten. Se kirjoittaa levylle halutun pituisen tiedoston ja tarkistaa että tieto tuli kirjoitettua oikein. Ongelmaa varten kirjoitin merkkijonosalaus (stream cipher) tyyppisen ohjelman. Näissä tuotetaan satunnaisbittejä siten että kaikki satunnaisuus saadaan avaimesta, ja sen perusteella annetaan näennäissatunnaisia merkkejä. Näin voidaan tuottaa täysin sama satunnaismerkkejä sisältävä merkkijono kaksi kertaa, ensin kirjoittamiseen ja sitten tarkistukseen. Tässä aluksi tuo merkkijonosalaus:
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2 // default is on
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 secure, more than one faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", sizeof(streamt), streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
}
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
//dumpline(stderr, sizeof(key), strlen(key));
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
Edellisessä ohjelmassa avaimen käsittely stream_open:issa on aika lähellä käyttäjäsalasanan salakirjoitusta. Siinä tehtävät useammat kierrokset (tässä 1024) vaikuttavat toisaalta siihen kuinka nopeasti käyttäjän lokkaantuminen toimii, ja toisaalta siihen kuinka nopeasti hyökkääjä voi kokeilla sanalistansa sanoja. Tietysti vielä tarvitaan mukaan satunnainen salt. Salthan on satunnainen merkkijono, joka talletetaan selväkielisenä salakirjoitetun salasanan kanssa ja sitä käytetään lisänä salasanan salakirjoitetuksessa. Salt varmistaa että sama salasana ei ole aina sama salakirjoitettuna. Tietenkin hyökkääjä tarvitsee tätä hyökkäystä varten salasanan salakirjoitettuna.
Tiedostonkirjoitustestiohjelma tekee tälläisen tulosteen: ajossa merkkijonosalauksen merkkijono (tai avain tai salasana) on tässä “kalakala”. (merkkijonosalauksista lisää hakusanoilla “stream cipher”)
Ensimmäisellä kierroksella kirjoitetaan ja varmistetaan tiedosto. Varmistuksessa (–verify) kirjoitettu tiedosto luetaan uudestaan ja verrataan välittömästi. Tiedostosta lasketaan tiiviste (hash). Tiivisteitä voidaan vertailla “hashing file” -rivillä ja “checking sha256” jälkeisellä rivillä. Voit tietysti tarkastaa hashin myös $ sha256sum newressutest10.106.rnd komennolla (vaihda tiedoston nimi).
Toisella kierroksella luetaan tiedosto ja vertaillaan taas “kalakala” salasanalla saatuun merkkijonoon. Exfat:in aiemmat ongelmat saa pois lisäämällä –sync ja –flush optiot. Minulle jäi kuitenkin tutina että exfat:issa on vielä joku muu ongelma. Jos haluat ihmetellä tätä voit ajaa newressutest10, newressutest ja newressu –sample ohjelmaa itse. (en varmaan ole aiemmin sanonut tätä mutta ajamasi ohjelmat tietysti pitää tarkistaa että ne tekevät suurinpiirtein mitä sanovat, ja että niissä ei ole haitallista materiaalia). Jos ajat ohjelmia exfat levyllä ja jätät –sync ja –flush optiot pois tulee erilaisia virheilmoituksia. Mielestäni ongelmat esiintyvät vain exfat:issa suuremmilla tiedostoilla (>128g). Tavallisilla levyillä en ole niitä havainnut.
Jos käytät –verify optiota, se tarvitsee myös –flush option.
$ ./newressutest10 --bytes1g --flush --verify --sync
bytes:1073741824(0x40000000)
filename:newressutest10.106.rnd
mbinblocks:1024
./newressutest10: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write and verify done.
./newressutest10: sample: hashing file, filename:newressutest10.106.rnd, hashfilename:newressutest10.106.rnd.sha256, sha256:8a8780a51695ae69c8e3d93e940583b42fbc9bd0f7fcf3513444d1c233da6629
./newressutest10: sample: checking sha256, filename:newressutest10.106.rnd
8a8780a51695ae69c8e3d93e940583b42fbc9bd0f7fcf3513444d1c233da6629 newressutest10.106.rnd
./newressutest10: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$
Seuraavassa ohjelman newressutest10 lähdekoodi: (uusi versio, jossa on muutettu merkkijonosalakirjoitusrutiineja ja comentoriviparametreja)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname;
static unsigned char *programname = "newressutest10 version 0.3 ©";
static unsigned char *copyright = "Copyright (c) 2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 1 * 1024 * 1024 * 1024
#define BLOCKSIZE 1024
#define BLOCKS FILESIZE / BLOCKSIZE
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
void dumpline(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
fprintf(fp1,"%02x", buf[c]);
}
void dump(FILE *fp1, unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(fp1,"\n");
fprintf(fp1,"%-10s", header);
}
fprintf(fp1," %02x", buf[c]);
}
fprintf(fp1,"\n");
fflush(fp1);
}
void compareblocks(FILE *fp1, int size, unsigned char *buffer, unsigned char *buffer2)
{
int c, count;
count = 0;
for(c = 0; c < size; c++) {
if(count > 31) {
fprintf(fp1,"\n");
count = 0;
}
if(buffer[c] == buffer2[c]) {
fprintf(fp1," %02x", buffer[c]);
count++;
} else {
fprintf(fp1," %02x/%02x", buffer[c], buffer2[c]);
count +=2;
}
}
}
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
}
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 --> secure, more than one --> faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", 32, streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
}
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stderr);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
//#define KILO 1000
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// 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";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%lld%c", ll, units[c]);
}
#define DEBUG32
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %lld", prevll);
fprintf(stderr,", multiplier: %lld", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%lld(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%lld(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%lld(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%lld(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x",final[c]);
}
}
#endif
unsigned char filename[128] = "";
void check_firstblock()
{
int count;
FILE *fp1;
static unsigned char *block = NULL;
static unsigned char *check_block = NULL;
if(block == NULL) {
if((block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for block\n", procname);
fflush(stderr);
exit(1);
}
}
if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot fopen file\n", procname);
fflush(stderr);
exit(1);
}
count = fread(block, 1, BLOCKSIZE, fp1);
fclose(fp1);
if(count < BLOCKSIZE) { // not a full block
return;
} else if(check_block == NULL) {
if((check_block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for check_block\n", procname);
fflush(stderr);
exit(1);
}
memcpy(check_block, block, BLOCKSIZE);
dump(stderr, "block1", BLOCKSIZE, block, 32);
} else {
if(memcmp(block, check_block, BLOCKSIZE)) {
fprintf(stderr,"%s: check_firstblock(): first block changed\n", procname);
dump(stderr, "block", BLOCKSIZE, block, 32);
exit(1);
}
}
}
#define KILO 1024
#define aDEBUG65 2
#define DEBUG68
int main(int argc, char *argv[])
{
int c, blocksize_set = 0, blocks_set = 0, filesize_set = 0;
unsigned long long ll, lllim, blocks = BLOCKS, filesize = FILESIZE;
unsigned int blocksize = BLOCKSIZE;
int errcount = 0, pros, prevpros, help = 0, stdoutflag = 0;
int writeflag = 1, verifyflag = 0, flushflag = 0, syncflag = 0, checkflag = 1, block1flag = 0;
unsigned char *buffer, *buffer2;
unsigned char key[128] = "kalakala";
FILE *fp1, *fp2;
procname = argv[0];
#define aDEBUG46
#ifdef DEBUG46
stream_open(0, "⚀⚁⚂⚃⚄⚅"); // utf8
stream_open(0, "Hasta la vista, baby (Arnold Schwarzenegger, T2)"); // pass phrase
stream_open(0, "abcdefghijklmnopqrstuvwxyz" // long password (key)
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz");
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) {// last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(!strncmp("-",argv[c], 1)) {
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--write", argv[c])) {
writeflag = !writeflag;
} else if(!strcmp("--verify", argv[c])) {
verifyflag = !verifyflag;
} else if(!strcmp("--flush", argv[c])) {
flushflag = !flushflag;
} else if(!strcmp("--sync", argv[c])) {
syncflag = !syncflag;
} else if(!strcmp("--check", argv[c])) {
checkflag = !checkflag;
} else if(!strcmp("--block1", argv[c])) {
block1flag = !block1flag;
} else if(!strncmp("--key", argv[c], 5)) {
if(*(argv[c] + 5) != '\0') {
strcpy(key, argv[c] + 5);
} else if(c + 1 < argc) {
strcpy(key, argv[c +1]);
}
fprintf(stderr,"key:%s", key);
fprintf(stderr,"\n");
fflush(stderr);
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--blocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
blocksize = getlonglong(argv[c] + 11);
} else if(c + 1 < argc) {
blocksize = getlonglong(argv[c + 1]);
c++;
}
blocksize_set = 1;
} else if(!strncmp("--blocks", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
blocks = getlonglong(argv[c] + 8);
} else if(c + 1 < argc) {
blocks = getlonglong(argv[c + 1]);
c++;
}
blocks_set = 1;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
help = 1;
}
}
}
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocks_set) {
blocks = (filesize + blocksize - 1) / blocksize; // round up
filesize = blocks * blocksize;
} else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks; // round up
filesize = blocks * blocksize;
}
if(filesize != blocks * blocksize) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", blocks:%llu", blocks);
fprintf(stderr,", blocksize:%u", blocksize);
fprintf(stderr,", filesize:%llu", filesize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG68
fprintf(stderr,"blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [-o filename]");
fprintf(stderr," [--stdout]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr," [--blocksize base-number-multiplier]");
fprintf(stderr,"\n\t[--blocks base-number-multiplier]");
fprintf(stderr,"\n\t");
fprintf(stderr,"[--write]");
fprintf(stderr," [--verify]");
fprintf(stderr," [--flush]");
fprintf(stderr," [--sync]");
fprintf(stderr," [--check]");
fprintf(stderr," [--block1]");
fprintf(stderr,"\n");
fprintf(stderr,"Options:\n");
fprintf(stderr,"\tWrite and check are on.\n");
fprintf(stderr,"\tVerify, flush, sync and block1 are off.\n");
fprintf(stderr,"\tOptions turn switch, so single --write means write off.");
fprintf(stderr,"\n\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\n");
fprintf(stderr,"Typical use:\n");
fprintf(stderr,"\t$ %s --filesize 128g (for regular drives)\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --flush --sync (for exfat)\n", procname);
fprintf(stderr,"\n");
fprintf(stderr,"Other use:\n");
fprintf(stderr,"\t$ %s --filesize 1g\n", procname);
fprintf(stderr,"\t$ %s --filesize 8g --verify\n", procname);
fprintf(stderr,"\t$ %s --filesize 64g --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --verify --flush --sync --block1\n", procname);
fprintf(stderr,"\t$ %s newressutest10.1.rnd --write --filesize 128g\n", procname);
exit(1);
} // end of if(help)
#define aDEBUG52
#ifdef DEBUG52
unsigned char buffer128[128];
stream_open(0, key);
stream_bytes(sizeof(buffer128), buffer128);
dump(stderr, "stream", sizeof(buffer128), buffer128, 32);
#endif
if((buffer = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
if((buffer2 = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer2)\n", procname);
exit(1);
}
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest10.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-");
else
fprintf(stderr,"filename:%s",filename);
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if(writeflag) {
if(stdoutflag == 1)
fp1 = stdout;
else if((fp1 = fopen(filename, "w")) == NULL) { // created datafile
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
if(verifyflag) {
if((fp2 = fopen(filename, "r")) == NULL) { // for verify file
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
verifyflag = 0;
}
}
prevpros = -1;
lllim = (long long) filesize / blocksize;
int mbinblocks = (1 * KILO * KILO) / BLOCKSIZE;
fprintf(stderr,"mbinblocks:%d\n", mbinblocks);
stream_open(0, key);
for(ll = 0; ll < lllim; ll++) {
stream_bytes(blocksize, buffer);
#ifdef DEBUG65
fprintf(stderr,"buffer ");
dumpline(stderr, 32, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
#ifdef FILE_HASH
HashUpdate(&hash, buffer, blocksize); // calculate hash
#endif
if(fwrite(buffer, 1, blocksize, fp1) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
int flushed = 0;
if(syncflag && (ll % mbinblocks == 0)) { // sync every 1m
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
sync();
//fsync(fileno(fp1));
}
if(verifyflag) {
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
if(fread(buffer2, 1, blocksize, fp2) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fprintf(stderr,"buffer2 ");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, blocksize)) {
fflush(stderr);
fprintf(stderr,"%s: verify error", procname);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * BLOCKSIZE, ll * BLOCKSIZE);
fprintf(stderr,", is:");
dumpline(stderr, 16, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, 16, buffer);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
} // end of if(verifyflag)
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lllim * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lllim; ll++)
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
if(syncflag) {
fflush(fp1);
sync();
}
if(!stdoutflag)
fclose(fp1);
if(syncflag) {
sync();
}
if(verifyflag)
fclose(fp2);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," write");
if(verifyflag)
fprintf(stderr," and verify");
fprintf(stderr," done.");
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
}
fprintf(stderr,", sha256:%s\n", hashstring);
if(filename[0] != '\0') {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
} // if(writeflag)
if(!stdoutflag && checkflag) {
if((fp2 = fopen(filename, "r")) != NULL) { // for reread
prevpros = -1;
lllim = (long long) filesize / blocksize;
stream_open(0, key);
for(ll = 0; ll < lllim; ll++) {
stream_bytes(blocksize, buffer);
if(fread(buffer2, 1, blocksize, fp2) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fflush(stdout);
fprintf(stderr,"bbuffer ");
dumpline(stderr, 32, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fprintf(stderr,"bbuffer2 ");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, blocksize)) {
fflush(stdout);
fprintf(stderr,"%s: check error", procname);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llu)", ll * BLOCKSIZE, ll * BLOCKSIZE);
fprintf(stderr,", data:");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, 32, buffer);
fprintf(stderr,"\n");
compareblocks(stderr, blocksize, buffer, buffer2);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lllim * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lllim; ll++)
fclose(fp2);
fflush(stdout);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," read and compare");
fprintf(stderr," done.");
fprintf(stderr,"\n");
} // end of if((fp2 = fopen(filename, "r")) != NULL)
} // end of if(checkflag)
}
Myös joihinkin postin aiempiin testailuohjelmiin (newressutest9 ja newressutest) on lisätty flush ja sync, päivitän niiden versiot tässä postissa uudempiin.
Lisätty uusi testiohjelma newressutest12, joka kirjoittaa ja lukee kiinteänpituisia tietueita. Tässä ohjelman tuloste: Tässä tulostetaan 1048576 (1m) riviä jotka sisältävät 10 merkkiä tietoa. Rivit tulostetaan heksajonona, joten yksi tulostettava rivi on 10 * 2 + 1 = 21 merkkiä pitkä. Tiedostosta tulee 1m * 21 = 21m kokoinen. Tässä tiedosto on kirjoitettu ja varmistettu (vaihe 1) ja luettu ja tarkistettu (vaihe 2). Muista lisätä –flush ja –sync exfat levyille.
$ ./newressutest12 --bytes10 --lines1m --verify --flush
base:10, multiplier:1, prevll:10, ll:10, totll:10
base:10, multiplier:1048576, prevll:1, ll:1048576, totll:1048576
lines:1048576(1M), bytes:10(10B), linesize:21(21B), filesize:22020096(21M)
filename:newressutest12.108.rnd
mbinlines:49932
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write and verify done.
./newressutest12: sample: hashing file, filename:newressutest12.108.rnd, hashfilename:newressutest12.108.rnd.sha256, sha256:a328ce8d2c4d98bb4ebf8ee3f8ac6d79e561722105789ceea68ae8837b974072
./newressutest12: sample: checking sha256, filename:newressutest12.108.rnd
a328ce8d2c4d98bb4ebf8ee3f8ac6d79e561722105789ceea68ae8837b974072 newressutest12.108.rnd
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$
Seuraavassa pätkä tulostettua tiedostoa: Tässä on tulostettu 10 merkin pituisia tietueita 10 kappaletta.
$ ./newressutest12 --bytes10 --lines10
base:10, multiplier:1, prevll:10, ll:10, totll:10
base:10, multiplier:1, prevll:10, ll:10, totll:10
lines:10(10B), bytes:10(10B), linesize:21(21B), filesize:210(210B)
filename:newressutest12.109.rnd
mbinlines:49932
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write done.
./newressutest12: sample: hashing file, filename:newressutest12.109.rnd, hashfilename:newressutest12.109.rnd.sha256, sha256:d57ad8172aa54ba800829370a98a241a19777aa6759401e6ff8b5577fcae7729
./newressutest12: sample: checking sha256, filename:newressutest12.109.rnd
d57ad8172aa54ba800829370a98a241a19777aa6759401e6ff8b5577fcae7729 newressutest12.109.rnd
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$ cat newressutest12.109.rnd
c0d1bc849d6fbb01fe79
507f611bfb4b0f739177
f574c12575e932b44ae3
29c32527df32c830651d
eb4880d6183b3cf1b3c2
a8dd883ba01e469d575c
cd8686453516ecf6251f
82adacdc30d74b31560a
7ccc5e834de655424463
c1e0bf91dd1c2ff14998
$
Seuraavalla voi testata piipun (‘|’) toimivuutta: datasta lasketun tiivisteen pitää mätsätä $sha256sum komennon tulostaman tiivisteen kanssa (c255de-alkuinen merkkijono).
$ ./newressutest12 --bytes16 --lines40g --stdout | sha256sum
string:'16', base:10, multiplier:1, prevll:16, ll:16, totll:16
string:'40g', base:10, multiplier:1073741824, prevll:40, ll:42949672960, totll:42949672960
lines:42949672960(40G), bytes:16(16B), linesize:33(33B), filesize:1417339207680(~1T)
filename:
mbinlines:31775
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write done.
./newressutest12: sample: hashing file, filename:, hashfilename:.sha256, sha256:c255de89c865c957bccc648ab7fbd9327eec338f36dfb96112ca3801fbbf2b71
c255de89c865c957bccc648ab7fbd9327eec338f36dfb96112ca3801fbbf2b71 -
$
Ja varsinainen ohjelma newressutest12.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname;
static unsigned char *programname = "newressutest12 version 0.6 ©";
static unsigned char *copyright = "Copyright (c) 2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 81 * 1024 * 1024
#define BINSIZE 40 // bytes per line
#define LINESIZE 81 // BINSIZE * 2 + 1
#define LINES 1 * 1024 * 1024
#define BLOCKSIZE 1024
int help = 0;
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
void dumpline(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
fprintf(fp1,"%02x", buf[c]);
}
void dump(FILE *fp1, unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(fp1,"\n");
fprintf(fp1,"%-10s", header);
}
fprintf(fp1," %02x", buf[c]);
}
fprintf(fp1,"\n");
fflush(fp1);
}
void compareblocks(FILE *fp1, int size, unsigned char *buffer, unsigned char *buffer2)
{
int c, count;
count = 0;
for(c = 0; c < size; c++) {
if(count > 31) {
fprintf(fp1,"\n");
count = 0;
}
if(buffer[c] == buffer2[c]) {
fprintf(fp1," %02x", buffer[c]);
count++;
} else {
fprintf(fp1," %02x/%02x", buffer[c], buffer2[c]);
count +=2;
}
}
}
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
}
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2 // default is on
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 secure, more than one faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", sizeof(streamt), streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
}
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
//dumpline(stderr, sizeof(key), strlen(key));
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
//#define KILO 1000
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// 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";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%lld%c", ll, units[c]);
}
#define DEBUG32 2
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%d", base);
fprintf(stderr,", prevll:%llu", prevll);
fprintf(stderr,", ll:%llu", ll);
fprintf(stderr,", multiplier:%llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%d", base);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x", final[c]);
}
}
#endif
unsigned char filename[128] = "";
void check_firstblock()
{
int count;
FILE *fp1;
static unsigned char *block = NULL;
static unsigned char *check_block = NULL;
if(block == NULL) {
if((block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for block\n", procname);
fflush(stderr);
exit(1);
}
}
if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot fopen file\n", procname);
fflush(stderr);
exit(1);
}
count = fread(block, 1, BLOCKSIZE, fp1);
fclose(fp1);
if(count < BLOCKSIZE) { // not a full block
return;
} else if(check_block == NULL) { // read and save original block
if((check_block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for check_block\n", procname);
fflush(stderr);
exit(1);
}
memcpy(check_block, block, BLOCKSIZE);
dump(stderr, "block1", BLOCKSIZE, block, 32);
} else { // compare to original block
if(memcmp(block, check_block, BLOCKSIZE)) {
fprintf(stderr,"%s: check_firstblock(): first block changed\n", procname);
dump(stderr, "block", BLOCKSIZE, block, 32);
exit(1);
}
}
}
#define aDEBUG65 2
#define DEBUG69 2
int main(int argc, char *argv[])
{
int c, filesize_set = 0, binsize_set = 0, linesize_set = 0, lines_set = 0;
unsigned long long ll, filesize = FILESIZE, lines = LINES;
unsigned int binsize = BINSIZE, linesize = LINESIZE;
int errcount = 0, pros, prevpros;
int writeflag = 1, stdoutflag = 0, verifyflag = 0, flushflag = 0;
int syncflag = 0, checkflag = 1, block1flag = 0;
unsigned char *binbuffer, *buffer, *buffer2;
unsigned char key[128] = "kalakala";
FILE *fp1, *fp2;
procname = argv[0];
#define aDEBUG46 2
#ifdef DEBUG46
ll = 1;
for(;;) {
fprintf(stderr,"ll:%llu", ll);
fprintf(stderr,", readablelonglong:");
readablelonglong(stderr, ll);
fprintf(stderr,"\n");
unsigned long long prevll = ll;
ll *= 2;
if(ll / 2 != prevll)
break;
}
#endif
#define aDEBUG48 2
#ifdef DEBUG48
stream_open(0, "⚀⚁⚂⚃⚄⚅"); // utf8
stream_open(0, "Hasta la vista, baby (Arnold Schwarzenegger, T2)"); // pass phrase
stream_open(0, "abcdefghijklmnopqrstuvwxyz" // long password (key)
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz");
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) {// last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(!strncmp("-",argv[c], 1)) { // option starting with hyphen
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--write", argv[c])) {
writeflag = !writeflag;
} else if(!strcmp("--verify", argv[c])) {
verifyflag = !verifyflag;
} else if(!strcmp("--flush", argv[c])) {
flushflag = !flushflag;
} else if(!strcmp("--sync", argv[c])) {
syncflag = !syncflag;
} else if(!strcmp("--check", argv[c])) {
checkflag = !checkflag;
} else if(!strcmp("--block1", argv[c])) {
block1flag = !block1flag;
} else if(!strncmp("--key", argv[c], 5)) {
if(*(argv[c] + 5) != '\0') {
strcpy(key, argv[c] + 5);
} else if(c + 1 < argc) {
strcpy(key, argv[c +1]);
}
fprintf(stderr,"key:%s", key);
fprintf(stderr,"\n");
fflush(stderr);
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--linesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
linesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
linesize = getlonglong(argv[c + 1]);
c++;
}
linesize_set = 1;
} else if(!strncmp("--lines", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
lines = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
lines = getlonglong(argv[c + 1]);
c++;
}
lines_set = 1;
} else if(!strncmp("--binsize", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
binsize = getlonglong(argv[c] + 9);
} else if(c + 1 < argc) {
binsize = getlonglong(argv[c + 1]);
c++;
}
binsize_set = 1;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
help = 1;
}
} // end of if(!strncmp("-",argv[c], 1
} // end of for(c = 1; c < argc; c++
if(!linesize_set)
linesize = binsize * 2 + 1;
else if(!binsize_set)
binsize = (linesize - 1) / 2;
if(linesize != binsize * 2 + 1) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", linesize:%u", linesize);
fprintf(stderr,", binsize:%u", binsize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(!filesize_set)
filesize = lines * linesize;
else if(!lines_set) {
lines = (filesize + linesize - 1) / linesize; // round up
filesize = lines * linesize;
} else if(!linesize_set) {
linesize = (filesize + lines - 1) / lines; // round up
filesize = lines * linesize;
}
if(filesize != lines * linesize) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", lines:%llu", lines);
fprintf(stderr,", linesize:%u", linesize);
fprintf(stderr,", filesize:%llu", filesize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG69
fprintf(stderr,"lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [-o filename]");
fprintf(stderr," [--stdout]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr," [--linesize base-number-multiplier]");
fprintf(stderr,"\n\t[--lines base-number-multiplier]");
fprintf(stderr," [--binsize base-number-multiplier]");
fprintf(stderr,"\n\t[--write]");
fprintf(stderr," [--verify]");
fprintf(stderr," [--flush]");
fprintf(stderr," [--sync]");
fprintf(stderr," [--check]");
fprintf(stderr," [--block1]");
fprintf(stderr,"\n");
fprintf(stderr,"Options:\n");
fprintf(stderr,"\tWrite and check are on.\n");
fprintf(stderr,"\tVerify, flush, sync and block1 are off.\n");
fprintf(stderr,"\tOptions turn switch, so single --write means write off.");
fprintf(stderr,"\n\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\n");
fprintf(stderr,"Typical use:\n");
fprintf(stderr,"\t$ %s --lines 128m (for regular drives)\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --flush --sync (for exfat)\n", procname);
fprintf(stderr,"\n");
fprintf(stderr,"Other use:\n");
fprintf(stderr,"\t$ %s --lines 1m\n", procname);
fprintf(stderr,"\t$ %s --lines 8m --verify\n", procname);
fprintf(stderr,"\t$ %s --lines 64m --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --verify --flush --sync --block1\n", procname);
fprintf(stderr,"\t$ %s newressutest12.1.rnd --write --lines 128m\n", procname);
exit(1);
} // end of if(help)
unsigned int dumplinelength = 32;
if(dumplinelength > linesize)
dumplinelength = linesize;
if((binbuffer = malloc(binsize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (binbuffer)\n", procname);
exit(1);
}
if((buffer = malloc(linesize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
if((buffer2 = malloc(linesize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer2)\n", procname);
exit(1);
}
#define aDEBUG52
#ifdef DEBUG52
unsigned char buffer128[128];
stream_open(0, key);
stream_bytes(sizeof(buffer128), buffer128);
dump(stderr, "stream", sizeof(buffer128), buffer128, 32);
#endif
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest12.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-");
else
fprintf(stderr,"filename:%s",filename);
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if(writeflag) {
if(stdoutflag == 1)
fp1 = stdout;
else if((fp1 = fopen(filename, "w")) == NULL) { // created datafile
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
if(verifyflag) {
if((fp2 = fopen(filename, "r")) == NULL) { // for verify file
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
verifyflag = 0;
}
}
prevpros = -1;
int mbinlines = (1 * KILO * KILO) / linesize;
fprintf(stderr,"mbinlines:%d\n", mbinlines);
stream_open(0, key);
for(ll = 0; ll < lines; ll++) {
stream_bytes(binsize, binbuffer);
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", binbuffer[c]);
buffer[linesize - 1] = '\n';
#ifdef DEBUG65
fprintf(stderr,"buffer ");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
#ifdef FILE_HASH
HashUpdate(&hash, buffer, linesize); // calculate hash
#endif
if(fwrite(buffer, 1, linesize, fp1) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
int flushed = 0;
if(syncflag && (ll % mbinlines == 0)) { // sync every 1m
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
sync();
//fsync(fileno(fp1));
}
if(verifyflag) {
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
if(fread(buffer2, 1, linesize, fp2) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fprintf(stderr,"buffer2 ");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, linesize)) {
fflush(stdout);
fprintf(stderr,"%s: verify error", procname);
fprintf(stderr,", lines:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * LINESIZE, ll * LINESIZE);
fprintf(stderr,", is:");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
} // end of if(verifyflag)
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lines; ll++)
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," write");
if(verifyflag)
fprintf(stderr," and verify");
fprintf(stderr," done.");
fprintf(stderr,"\n");
fflush(stderr);
fflush(fp1);
sync();
if(!stdoutflag)
fclose(fp1);
if(verifyflag)
fclose(fp2);
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n", hashstring);
fclose(fp1);
}
}
fprintf(stderr,", sha256:%s\n", hashstring);
if(filename[0] != '\0') {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
} // if(writeflag)
if(!stdoutflag && checkflag) {
if((fp2 = fopen(filename, "r")) != NULL) { // for reread
prevpros = -1;
stream_open(0, key);
for(ll = 0; ll < lines; ll++) {
stream_bytes(binsize, binbuffer);
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", binbuffer[c]);
buffer[linesize - 1] = '\n';
if(fread(buffer2, 1, linesize, fp2) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fflush(stderr);
fprintf(stderr,"bbuffer ");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,"\n");
fprintf(stderr,"bbuffer2 ");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, linesize)) {
fflush(stdout);
fprintf(stderr,"%s: check error", procname);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * linesize, ll * linesize);
fprintf(stderr,", data:");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,"\n");
compareblocks(stderr, linesize, buffer, buffer2);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lllim; ll++)
fclose(fp2);
fflush(stdout);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," read and compare");
fprintf(stderr," done.");
fprintf(stderr,"\n");
fflush(stderr);
} // end of if((fp2 = fopen(filename, "r")) != NULL)
} // end of if(checkflag)
}
Suurin osa tästä postista on ollut exfat debukkailua, mutta taas kerran tuntuu siltä että “pasianssi” menee läpi. Eli että nuo db_get ja db_put rutiinit toimivat tosiaan sovelluksen koodauksessa. Tällä hetkellä mielessäni on idea että sovellukseen tarvittavat kyselyt ja rivit nimetään sovelluksen “sisäisillä” nimillä (header, lines, headerfields, linesfields, session, log jne…) ja niille lisätään järjestysnumero. Järjestysnumerolla voidaan lukea useampirivisen kyselyn halutun rivin kenttä. Esimerkiksi tilausrivit, taulukon sarakkeiden nimet, otsakkeen kenttien nimet.
Sitten newressu sorsa kokonaisuudessaan, ensin Makefile:
CC = cc
CFLAGS = -g -Wall -Wno-pointer-sign
newressuobjs = newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o
sha256objs = sha256.m.o
all: newressu sha256
newressu: $(newressuobjs)
cc $(CFLAGS) $(newressuobjs) -o newressu -lssl -lcrypto -lm
sha256: $(sha256objs)
cc $(CFLAGS) $(sha256objs) -o sha256
%.mfs.o: %.c
$(CC) $(CFLAGS) -DMAIN -DFORT -DSHA256 -c -o $@ $<
%.fs.o: %.c
$(CC) $(CFLAGS) -DFORT -DSHA256 -c -o $@ $<
%.m.o: %.c
$(CC) $(CFLAGS) -DMAIN -c -o $@ $<
%.p.o: %.c
$(CC) $(CFLAGS) -DPSEUDORESSU -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *~ \#*\# *.o
newressu.c
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
//#define SHA256 2 // in Makefile
#include "sha256.h"
//#define MAIN 2 // in Makefile
extern unsigned char *procname;
static unsigned char *programname = "Newressu version 3.9 ©";
static unsigned char *copyright = "Copyright (c) 2013-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
int newressu_output = 0;
void ressu_dump(unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%-10s", header);
}
fprintf(stdout," %02x", buf[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
}
static unsigned long periods[1024];
static unsigned long genbytes = 0;
static unsigned long clockbytes = 0;
int verbose = 0;
int size = 5, type = 10;
#define ALL_SLICE 64 // orig 64
#define RESSUT_SLICES 32 // orig 32
#define RESSUT_BYTES (RESSUT_SLICES * ALL_SLICE) // 2048 (32 * 64)
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16 * 1024
#define GENT_SLICES 16 // orig 16
#define GENT_SIZE (GENT_SLICES * ALL_SLICE) // 1024 (16 * 64)
#define SAMPLE_SLICES 16 // orig 16
#define SAMPLE_BLOCKSIZE (SAMPLE_SLICES * ALL_SLICE) //orig 1024
static int ressut_bytes = (RESSUT_SLICES * ALL_SLICE); // orig 2048
static int ressut_bits1_needed = RESSUT_SLICES * 8; // orig 256
static int ressut_bits2_needed = RESSUT_SLICES * 32; // orig 1024
static int ressut_bits3_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits4_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits5_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits6_needed = RESSUT_SLICES * 64 * 2; // orig 2048 * 2
static int ressut_bits7_needed = RESSUT_SLICES * 64 * 8; // orig 2048 * 8
int rndbits1 = 0,
rndbits2 = 0,
rndbits3 = 0,
rndbits4 = 0,
rndbits5 = 0,
rndbits6 = 0,
rndbits7 = 0;
static int stats = 0;
#define DEBUG_SORTED 2
unsigned long long ressu_useconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec + 1000000 * tv.tv_sec);
}
static unsigned char ressu_clockbyte2() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
#define FIXEDCLOCKCHAINLENGTH 50 // orig 50
unsigned int fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
static unsigned char ressu_fixedclock() /* JariK 2022 */
{
static unsigned int clockbyte = 1, counter = 0;
if(counter == 0) {
clockbyte++;
counter += fixedclockchainlength;
}
counter--;
return(clockbyte & 0xff);
}
static unsigned char ressu_clock()
{
return ressu_clockbyte2();
//return ressu_clockbyte2() ^ ressu_fixedclock();
}
unsigned char (*clockfunc)() = &ressu_clock;
void ressu_setclock(int clockmode)
{
if(!clockmode)
clockfunc = &ressu_clock;
else
clockfunc = &ressu_fixedclock;
}
#define aDEBUG2A 2
#define aDEBUG2B 2
#define aDEBUG2C 2
static unsigned char *ressuct; // ressu random buffer lookup
static unsigned int ressuct_bytes;
static unsigned char ch;
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
rando = rando +
//clockbytes +
//genbytes +
//time(NULL) +
//clock() +
ressu_useconds() +
ch * ch +
ressu_clock();
#ifdef DEBUG2C
fprintf(stderr," %u", rando % ressuct_bytes);
newressu_output = 1;
#endif
return(rando);
}
unsigned long cblocks = 0;
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[257];
static unsigned int count = 0;
// dividing clock stream into blocks
// and reversing every other block
if(reverse) { // reverse
// reverse clock chain block
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"rev: %03x ", count);
#endif
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)(); // block bytes
#ifdef DEBUG2A
fprintf(stdout," %02x", reversebytes[c]);
newressu_output = 1;
#endif
}
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
cblocks++;
}
// get reversed byte to return
ch = reversebytes[--count]; // reverse
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
#endif
if(count == 0) {
reverse = 0; // back to copy
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
} else { // copy
// copy clock chain block as is
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"copy: %03x ", count);
#endif
cblocks++;
}
// get byte to be copied
ch = (*clockfunc)();
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
newressu_output = 1;
#endif
if(--count == 0) {
reverse = 1; // back to reverse
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
}
#ifdef DEBUG2A
fflush(stdout);
#endif
// statistics for theoretical
// random bits calculation (rndbits?)
static int prevbyte = -1, clockcount = 0;
if(prevbyte == -1)
prevbyte = ch;
if(prevbyte != ch) {
periods[clockcount]++;
clockbytes += clockcount;
#ifdef DEBUG2B
fprintf(stdout," %d", clockcount);
newressu_output = 1;
#endif
clockcount = 0;
prevbyte = ch;
}
clockcount++;
return(ch);
}
#define RR8(byte, bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte, bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )
#define aDEBUG5A 2
#define aDEBUG5B 2
#define aDEBUG5C 2
#define aLOWCLOCKBITONLY 2 // off by default
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
{
int c, d;
unsigned char e;
static int f = 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
#ifdef LOWCLOCKBITONLY
buffer[d] = e ^ (ressu_clockbyte() & 1);
#else
buffer[d] = e ^ ressu_clockbyte();
#endif
}
#ifdef DEBUG5A
if(newressu_output)
fprintf(stdout, "\n");
ressu_dump("ressu 1", 32, buffer, 32); // first 32 bytes
fflush(stdout);
#endif
for(d = 0; d < size; d++) {
#ifdef DEBUG5B
fprintf(stdout,"d:%d", d);
fprintf(stdout,", f:%d", f);
fprintf(stdout,", bufferd:%d", buffer[d]);
fprintf(stdout,", bufferf:%d", buffer[f]);
fprintf(stdout,"\n");
#endif
f = (f + buffer[d] + 2) % size; // +2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
#ifdef DEBUG5A
if(newressu_output)
fprintf(stdout,"\n");
ressu_dump("ressu 2", 32, buffer, 32); // first 32 bytes
fflush(stdout);
#endif
#ifdef DEBUG5C
fprintf(stdout,"\n");
ressu_dump("ressu 3", size, buffer, 32); // whole buffer
fflush(stdout);
#endif
}
}
#ifdef OLD1
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
{
int c, d;
unsigned char e, ch;
static int f = 0;
#ifdef OLD1
static int prevch = -1, count = 0;
#endif
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
ch = ressu_clockbyte();
//ch = ressu_clockbyte() & 1;
buffer[d] = e ^ ch;
#ifdef OLD1
if(prevch == -1)
prevch = ch;
if(prevch != ch) {
periods[count]++;
clockbytes += count;
#ifdef DEBUG2B
fprintf(stdout," %d", count);
newressu_output = 1;
#endif
count = 0;
prevch = ch;
}
count++;
#endif
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout, "\n");
ressu_dump("single 1", size, buffer, 32); // first 32 bytes
#endif
for(d = 0; d < size; d++) {
//fprintf(stdout,"\n");
//ressu_dump("single 3", size, buffer, 32); // first 32 bytes
f = (f + buffer[d]) % size;
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout,"\n");
ressu_dump("single 2", size, buffer, 32); // first 32 bytes
#endif
}
}
#endif
void ressu_genbytes_single(int size, unsigned char *buffer)
{
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
cblocks = 0;
ressu_genbytes_single_do(size, buffer);
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:1");
long chains = 0;
for(int e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
#ifdef DEBUG7
ressu_dump("single", size, buffer, 32);
#endif
genbytes += size;
}
void ressu_genbytes_fast(int size, unsigned char *buffer)
{
int d, e, f;
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
cblocks = 0;
for(d = 0; d < RESSU_MIN_ROUNDS ||
rndbits2 < ressut_bits2_needed ||
d < RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
ressu_genbytes_single_do(size, buffer);
}
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
#ifdef DEBUG_SORTED
fprintf(stderr, ", 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(stderr," %d", g);
}
#endif
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
#ifdef DEBUG7
ressu_dump("fast", size, buffer, 32);
#endif
genbytes += size;
}
#define aDEBUG3B 2
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c, d, e, f;
static unsigned char ressut[RESSUT_BYTES];
static int ressut_first = 1,
ressut_pos = 0,
ressut_f = 0;
unsigned long prevperiods[1024];
ressuct = ressut; // ressu random buffer lookup
ressuct_bytes = ressut_bytes; // table used in ressu_genbytes_single_do
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;
}
rndbits1 = 0;
rndbits2 = 0;
rndbits3 = 0;
rndbits4 = 0;
rndbits5 = 0;
rndbits6 = 0;
rndbits7 = 0;
cblocks = 0;
int lim, lim1 = 0, lim2 = 0;
int lim1a, lim1b;
int high1, high2;
int rndbits3high;
int rndbits4highdigits;
int rndbits6high;
int rndbits6pos;
int rndbits7high;
for(d = 0;
rndbits1 < ressut_bits1_needed ||
rndbits2 < ressut_bits2_needed ||
rndbits3 < ressut_bits3_needed ||
rndbits4 < ressut_bits4_needed ||
rndbits5 < ressut_bits5_needed ||
rndbits6 < ressut_bits6_needed ||
rndbits7 < ressut_bits7_needed ||
d < RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
#define aDEBUG6 2
//
// calculate rndbits1
//
// save previous round
for(e = 0; e < 1024; e++) {
prevperiods[e] = periods[e];
}
#ifdef DEBUG3B
fprintf(stdout,"rndbits1:%d", rndbits1);
fprintf(stdout,", rndbits2:%d", rndbits2);
fprintf(stdout,", rndbits3:%d", rndbits3);
fprintf(stdout,", rndbits4:%d", rndbits4);
fprintf(stdout,", rndbits5:%d", rndbits5);
fprintf(stdout,", rndbits6:%d", rndbits6);
fprintf(stdout,", rndbits7:%d", rndbits6);
fprintf(stdout,"\n");
#endif
ressu_genbytes_single_do(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 rndbits1
#define aDEBUG6 2
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
}
}
//
// calculate rndbits3
//
#define aDEBUG8 2
rndbits3high = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high < periods[e])
rndbits3high = periods[e];
}
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e]) {
rndbits3 += periods[e];
}
}
//
// calculate rndbits4
//
#define aDEBUG9 2
rndbits4highdigits = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
rndbits4highdigits = (int)log10((double)periods[e]) + 1;
}
}
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
rndbits4 += periods[e];
}
}
//
// calculate rndbits5
//
#define aDEBUG10 2
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
rndbits5 += periods[e];
}
//
// calculate rndbits6
//
#define aDEBUG11 2
rndbits6high = 0;
rndbits6pos = 0;
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high < periods[e]) {
rndbits6high = periods[e];
rndbits6pos = e;
}
}
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] && periods[e] > 0) {
if(rndbits6pos > e)
rndbits6 += log2((double)rndbits6pos - e) * periods[e];
else
rndbits6 += log2((double)e - rndbits6pos) * periods[e];
}
}
//
// calculate rndbits7
//
#define aDEBUG12 2
rndbits7high = 0;
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high < periods[e])
rndbits7high = periods[e];
}
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] && periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
}
}
} // for(d=0;
//
// debug display for rndbits1
//
#ifdef DEBUG6
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits1+prev:%d", rndbits1);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits3
//
#ifdef DEBUG8
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e] &&
periods[e] > 0) {
rndbits3 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits3+prev:%d", rndbits3);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits4
//
#ifdef DEBUG9
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1 &&
periods[e] > 0) {
rndbits4 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits4+prev:%d", rndbits4);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits5
//
#ifdef DEBUG10
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
rndbits5 += periods[e];
fprintf(stderr,", rndbits5+prev:%d", rndbits5);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits6
//
#ifdef DEBUG11
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] &&
periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%lu", periods[e]);
double l2;
if(rndbits6pos > e) {
fprintf(stderr,", pos-e:%d", rndbits6pos - e);
l2 = log2((double)rndbits6pos - e);
} else {
fprintf(stderr,", e-pos:%d", e - rndbits6pos);
l2 = log2((double)e - rndbits6pos);
}
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
rndbits6 += l2 * periods[e];
fprintf(stderr,", rndbits6+prev:%d", rndbits6);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits7
//
#ifdef DEBUG12
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] &&
periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", high-prev:%ld", rndbits7high-periods[e]);
double l2=log2((double)rndbits7high-periods[e]);
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
fprintf(stderr,", rndbits7+prev:%d", rndbits7);
fprintf(stderr,"\n");
}
}
#endif
if(stats) {
if(newressu_output == 1)
fprintf(stderr,"\n");
newressu_output = 0;
//
// display statistics
//
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
#ifdef DEBUG_SORTED
fprintf(stderr, ", 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(stderr," %d", g);
}
#endif
fprintf(stderr, ", ressut size:%d", ressut_bytes);
fprintf(stderr, ", high1:%d", high1);
fprintf(stderr, ", high2:%d", high2);
fprintf(stderr, ", lim1a:%d", lim1a);
fprintf(stderr, ", lim1b:%d", lim1b);
fprintf(stderr, ", lim1:%d", lim1);
fprintf(stderr, ", lim2:%d", lim2);
fprintf(stderr, ", div:%f", (double)lim2 / lim1);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits1:%d", rndbits1);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, ", rndbits3high:%d", rndbits3high);
fprintf(stderr, ", rndbits3:%d", rndbits3);
fprintf(stderr, ", rndbits4highdigits:%d", rndbits4highdigits);
fprintf(stderr, ", rndbits4:%d", rndbits4);
fprintf(stderr, ", rndbits5:%d", rndbits5);
fprintf(stderr, ", rndbits6high:%d", rndbits6high);
fprintf(stderr, ", rndbits6:%d", rndbits6);
fprintf(stderr, ", rndbits7high:%d", rndbits7high);
fprintf(stderr, ", rndbits7:%d", rndbits7);
fprintf(stderr, "\n");
fflush(stderr);
}
} // 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++)
if(verbose) {
fprintf(stdout,"ressu ");
for(c = 0; c < size; c++) {
if(c > 0 && c % 32 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x", buffer[c]);
newressu_output = 1;
}
fprintf(stdout,"\n");
}
#ifdef DEBUG7
ressu_dump("genbytes", size, buffer, 32);
#endif
genbytes += size;
}
#define aDEBUG1 2
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
#ifdef DEBUG1
ressu_dump("cvar", cvarsize + 1, cvar, 32);
#endif
}
#define aCVARRANDOMSTART 2 // off by default
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
#ifdef CVARRANDOMSTART
ressu_genbytes(8, (unsigned char *)&cvar);
#endif
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
#ifdef SHA256
#define PSEUDORESSU_LIMIT 1048576 // limit between rekeys
#define TOPUP_BYTES 32*1024 // bytes between topups
#define TOPUP_SIZE 32 // topup size in bytes (256 bits)
#define aTOPUP_TWICE 2 // off by default
static unsigned char pseudoressu_key[HashLen]; // 32 bytes, 256 bits
static void pseudoressu_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
static void pseudoressu_addrandomness(int size, unsigned char *buffer)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashUpdate(&hash, buffer, size);
HashFinal(pseudoressu_key, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
#define aDEBUG23 2
static void pseudoressu_topup()
{
unsigned char topup[TOPUP_SIZE]; // 256 bits
ressu_genbytes(sizeof(topup), topup);
#ifdef DEBUG23
ressu_dump("topup", sizeof(topup), topup, 32);
#endif
pseudoressu_addrandomness(sizeof(topup), topup);
memset(&topup, 0, sizeof(topup)); // forget hash
}
void pseudoressu_bytes(int size, unsigned char *buffer) // JariK 2022
{
unsigned int n, blockbytes = 0;
unsigned char digest[HashLen]; // 256 bits
static int init = 1, topup_counter = 0;
if(verbose)
fprintf(stdout,"pseudoressu");
while(size > 0) {
if(topup_counter <= 0) {
if(init) {
ressu_genbytes(sizeof(pseudoressu_key), pseudoressu_key); // set first key
#ifdef DEBUG23
ressu_dump("first key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
init = 0;
}
pseudoressu_topup(); // add randomness to key
#ifdef TOPUP_TWICE
pseudoressu_topup(); // add randomness to key
#endif
topup_counter = TOPUP_BYTES;
blockbytes = 0;
} // end of if(topup_counter <= 0)
pseudoressu_internalbytes(digest); // get random bits using the key
n = (size < sizeof(digest) ? size : sizeof(digest));
#ifdef DEBUG23
ressu_dump("olddata", n, buffer, 32);
ressu_dump("bytes", n, digest, 32);
#endif
for(int c = 0; c < n; c++)
buffer[c] ^= digest[c];
#ifdef DEBUG23
ressu_dump("newdata", n, buffer, 32);
#endif
if(verbose) {
fprintf(stdout," ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
newressu_output = 1;
}
buffer += n;
size -= n;
blockbytes += n;
if(blockbytes >= PSEUDORESSU_LIMIT && size > 0) {
pseudoressu_internalbytes(pseudoressu_key); // replace key with new random one
#ifdef DEBUG23
ressu_dump("rekey", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
blockbytes = 0;
}
topup_counter -= n;
} // end of while(size>0)
pseudoressu_internalbytes(pseudoressu_key); // replace key with new random one
#ifdef DEBUG23
ressu_dump("new key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
}
#endif
void newressu_version()
{
fprintf(stderr, "%s", programname); // touch these outside #ifdef MAIN
fprintf(stderr, ", %s", copyright);
}
#ifdef MAIN
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <malloc.h>
#include "newressu.h"
#define SAMPLE_WRITE 2 // off by default
#define SAMPLE_HASH 2 // on by default (for now)
#define SAMPLE_SYNC 2 // on by default (for now (exfat))
#define aUSE_RANDOM 2
#define USE_TIMER 2
#define aUSE_DUMMY 2
#ifdef FORT
#include "fort.h"
#endif
static unsigned char samplefilename[128] = "newressusample%d.rnd";
static unsigned char urandomfilename[128] = "/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128] = "/dev/random";
#endif
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);
}
}
int input = 0;
int clockmode = 0; // 0 = normal, 1 = fixed
char *randomgen[] = {
"ressu", "pseudoressu", "fastressu", "singleressu", "4",
"5", "fort", "fortxor", "rdrand", "rdseed",
"urandom", "random", "dummy"
};
static unsigned char gent[GENT_SIZE]; // orig 1024
static unsigned int gent_pos = 0;
void gent_clear()
{
memset(gent, 0, sizeof(gent));
}
#define aDEBUG17 2
#define aDEBUG18 2
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
#ifdef DEBUG23
ressu_dump("oldgent", 32, gent, 32); // first 32 bytes
#endif
gent_clear();
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(gent), gent);
#ifdef SHA256
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_FASTRESSU) // ressu_fast
ressu_genbytes_fast(sizeof(gent), gent);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(gent), gent);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(sizeof(gent), gent);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(sizeof(gent), gent);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(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
else {
fprintf(stdout,"%s: mode '%d'(%s) not available\n",
procname, input, randomgen[input]);
exit(2);
}
#ifdef DEBUG23
ressu_dump("newgent", 32, gent, 32); // first 32 bytes
#endif
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
#ifdef DEBUG18
fprintf(stdout, "{%02x}", ch);
#endif
return(ch);
}
#define aDEBUG19 2
#define aDEBUG24 2
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
#ifdef DEBUG24
fprintf(stdout,"/");
#ifdef DEBUG19
fprintf(stdout,"%d bytes: ", bytes);
#endif
if(type == 2)
fprintf(stdout,"%lx", word);
else if(type == 8)
fprintf(stdout,"%lo", word);
else if(type == 10)
fprintf(stdout,"%lu", word);
else if(type == 16)
fprintf(stdout,"%lx", word);
else
fprintf(stdout,"%lu", word);
fprintf(stdout,"/");
fflush(stdout);
#endif
return(word);
}
static int cursor_on = 0;
unsigned char cursor[4] = { '|', '/', '-', '\\' };
long int prev_secs = -1;
int crs = 0;
void stat_line_cursor_start()
{
fprintf(stderr,"%c", cursor[crs]);
fflush(stderr);
//prev_secs = -1;
cursor_on = 1;
}
void stat_line_cursor()
{
long int secs;
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;
}
}
void stat_line_cursor_remove()
{
if(cursor_on) {
fprintf(stderr, "\b \b");
fflush(stderr);
//prev_secs = -1;
}
cursor_on = 0;
}
#include <stdarg.h>
#define aDEBUG31 2
unsigned char *procname = NULL;
static unsigned char *prev_stat_line = NULL;
static unsigned char *stat_line = NULL;
static size_t stat_line_length = 0;
static void stat_line_begin()
{
if(stat_line != NULL)
stat_line[0] = '\0';
}
static void stat_line_printf(const unsigned char *format, ...)
{
int count;
va_list args;
static unsigned char *buffer = NULL;
static size_t buffer_length = 0;
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
if(buffer_length < count) {
buffer_length = count;
buffer = realloc(buffer, buffer_length);
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
}
count = 0;
if(stat_line != NULL)
count += strlen(stat_line);
count += strlen(buffer);
count++;
if(stat_line_length < count) {
unsigned char *stat_line2 = stat_line;
stat_line_length = count;
stat_line = realloc(stat_line, stat_line_length);
prev_stat_line = realloc(prev_stat_line, stat_line_length);
if(stat_line2 == NULL) {
stat_line[0] = '\0';
prev_stat_line[0] = '\0';
}
}
strcat(stat_line, buffer);
}
#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_get_readable(unsigned char buf10[10], unsigned long length)
{
int c, low;
double length2;
// 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' ||
units[c] == 'M' ||
units[c] == 'G' ||
units[c] == 'T')
sprintf(buf10, "%.3f", length2);
else if(length == length2)
sprintf(buf10, "%ld", length);
else
sprintf(buf10, "%.1f", length2);
if(strchr(buf10, '.') != NULL) {
int d;
d = strlen(buf10) - 1;
while(d > 3 && isdigit(buf10[d])) {
buf10[d] = '\0';
d--;
}
if(buf10[strlen(buf10)-1] == '.')
buf10[strlen(buf10)-1] = '\0';
}
if(units[c] != 'B') {
char unit[10];
sprintf(unit,"%cB",units[c]);
strcat(buf10, unit);
}
break;
}
length2 = (double)length / READABLE_NUMBER_DIVIDER;
length /= READABLE_NUMBER_DIVIDER;
low = 1;
}
}
static void stat_line_readable(unsigned long length)
{
unsigned char buf10[10];
stat_line_get_readable(buf10, length);
stat_line_printf("%s", buf10);
}
void stat_line_end()
{
int c, d;
if(stat_line != NULL && strcmp(prev_stat_line, stat_line)) { // status line changed
stat_line_cursor_remove();
#ifdef DEBUG31
fprintf(stderr, "\n");
#else
fprintf(stderr, "\r");
#endif
fprintf(stderr,"%s", stat_line);
fflush(stderr);
// previous line longer than this one,
// overwrite with spaces and backspace to
// end
d = strlen(prev_stat_line) - strlen(stat_line) + 1; // cursor too
if(d > 0) { // previous line longer
for(c = 0; c < d; c++) {
#ifdef DEBUG31
fprintf(stderr, "*");
#else
fprintf(stderr, " "); // print spaces
#endif
}
#ifndef DEBUG31
for(c = 0; c < d; c++)
fprintf(stderr, "\b"); // and backspaces
#endif
}
strcpy(prev_stat_line, stat_line);
//if(strlen(stat_line) > 0)
//stat_line_cursor_start();
//stat_line_cursor();
}
}
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// 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";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%lld%c", ll, units[c]);
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
#define DEBUG32
//#define KILO 1000
#define KILO 1024
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %lld", prevll);
fprintf(stderr,", multiplier: %lld", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%lld(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%lld(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%lld(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%lld(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
#ifdef SAMPLE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x",final[c]);
}
}
#endif
static int sample = 0, dieharder = 0; // randomness analysis
// try randomness analysis with: $ dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t oldhandler;
void sample_handler()
{
static int times = 0;
times++;
fprintf(stderr,"Ctrl-c pressed %d times\n", times);
if(times >= 10) {
signal(SIGINT, oldhandler);
exit(1);
}
}
#define FILESIZE 1 * 1024 * 1024 * 1024
#define BLOCKSIZE 128 * 1024
#define BLOCKS 8 * 1024
unsigned long long filesize = FILESIZE, blocks = BLOCKS;
unsigned int blocksize = BLOCKSIZE;
int filesize_set = 0, blocks_set = 0, blocksize_set = 0;
void dump_sample() // & dieharder analysis
{
#define STAT_LINE_BLOCK 2 // on by default
#define STAT_LINE_WRITTEN 2 // on by default
#define STAT_LINE_SPEED 2 // on by default
#define STAT_LINE_NOW 2 // on by default
#define STAT_LINE_LEFT 2 // on by default
#define STAT_LINE_READY 2 // on by default
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
unsigned long long c;
unsigned char *buffer, filename[128], command[1024];
FILE *fp1;
time_t secondsstart, secondsnow;
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, samplefilename, c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
unsigned char filename2[138];
sprintf(filename2,"%s.dieharder",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef SAMPLE_HASH
sprintf(filename2,"%s.sha256",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks;
filesize = blocks * blocksize;
} else if(!blocks_set) {
blocks = (filesize + blocksize - 1)/ blocksize;
filesize = blocks * blocksize;
}
if(blocks * blocksize != filesize) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", blocks:%llu", blocks);
fprintf(stderr,", blocksize:%u", blocksize);
fprintf(stderr,", filesize:%llu", filesize);
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
fprintf(stderr,"blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", blocks:%lld(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", filesize:%lld(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
if((buffer = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: sample: cannot allocate memory (buffer)\n", procname);
exit(1);
}
// you have to press ctrl-c 10 times
oldhandler = signal(SIGINT, sample_handler);
#define DEBUG58 2 // default on (for now)
#ifdef DEBUG58
fprintf(stderr,"%s: sample: writing file", procname);
fprintf(stderr,", filename:%s", filename);
#ifndef SAMPLE_WRITE
fprintf(stderr,", no write");
#endif
fprintf(stderr,"\n");
#endif
#ifdef SAMPLE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // calculate hash
#endif
if((fp1 = fopen(filename, "a")) != NULL) {
secondsstart = time(NULL);
unsigned long long clim = (unsigned long long) filesize / blocksize;
int mbinblocks = (1 * KILO * KILO) / BLOCKSIZE;
for(c = 0; c < clim; c++) {
secondsnow = time(NULL);
//if(1) {
// 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();
int print = 0;
#ifdef STAT_LINE_BLOCK
stat_line_printf("%s", randomgen[input]);
// print block from 0 to 8192
stat_line_printf("block %d", c);
print = 1;
#endif
#ifdef STAT_LINE_WRITTEN
// print written
if(print)
stat_line_printf(", ");
stat_line_printf("written ");
stat_line_readable((unsigned long)c * blocksize);
print = 1;
#endif
if(c > 0) {
#ifdef STAT_LINE_SPEED
// print speed
if(print)
stat_line_printf(", ");
if(secondsnow - secondsstart > 1.0)
stat_line_readable((unsigned long)((double)c * blocksize / (secondsnow - secondsstart)) );
else
stat_line_readable((unsigned long)((double)c * blocksize));
stat_line_printf("/sec");
print = 1;
#endif
#if defined STAT_LINE_NOW || \
defined STAT_LINE_READY
char timebuf[128];
#endif
#ifdef STAT_LINE_READY
char timebuf2[128];
#endif
#ifdef STAT_LINE_NOW
// print now
if(print)
stat_line_printf(", ");
stat_line_printf("now");
strftime(timebuf, sizeof(timebuf), TIMEFORMAT2,
localtime((time_t *)&secondsnow));
stat_line_printf(" %s", timebuf);
print = 1;
#endif
#ifdef STAT_LINE_LEFT
// print left
unsigned long int secondsleft = (int)((((double)secondsnow - secondsstart) / c) * (clim - c) );
unsigned long int secondsleft2;
unsigned long int temp;
int timeprinted = 0;
//int hoursprinted = 0;
if(print)
stat_line_printf(", ");
secondsleft2 = secondsleft;
stat_line_printf("left");
temp = secondsleft2 / (24 * 3600); // days
if(temp > 0) {
timeprinted = 1;
stat_line_printf(" %dd", temp);
secondsleft2 -= temp * (24 * 3600);
}
temp = secondsleft2 / 3600; // hours
if(temp > 0 || timeprinted) {
timeprinted = 1;
//hoursprinted = 1;
stat_line_printf(" %02dh", temp);
secondsleft2 -= temp * 3600;
}
temp = secondsleft2 / 60; // minutes
if(temp > 0 || timeprinted) {
timeprinted = 1;
stat_line_printf(" %02dm", temp);
secondsleft2 -= temp * 60;
}
temp = secondsleft2; // seconds
if(!timeprinted) {
stat_line_printf(" %d seconds", temp);
}
print = 1;
#endif
#ifdef STAT_LINE_READY
long int secondsend = (int)secondsstart + ((((double)secondsnow - secondsstart) / c) * clim);
// print end date if different
if(print)
stat_line_printf(", ");
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);
print = 1;
#endif
}
stat_line_end();
stat_line_cursor_start();
//} // end of if(c > 0
// do the work
stat_line_cursor();
memset(buffer, 0, blocksize);
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(blocksize, buffer);
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(blocksize, buffer);
else if(input == INPUT_FASTRESSU) // ressu fast
ressu_genbytes_fast(blocksize, buffer);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(blocksize, buffer);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(blocksize, buffer);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(blocksize, buffer);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(blocksize, buffer);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(blocksize, buffer);
#endif
else if(input == INPUT_URANDOM) // urandom
readfile_xor(blocksize, buffer, urandomfilename);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
readfile_xor(blocksize, buffer, randomfilename);
#endif
#ifdef USE_DUMMY
else if(input == INPUT_DUMMY) {
// no generator
}
#endif
else {
fprintf(stdout,"\n%s: mode '%d'(%s) not available\n",
procname, input, randomgen[input]);
exit(2);
}
#ifdef SAMPLE_HASH
HashUpdate(&hash, buffer, blocksize); // calculate hash
#endif
#ifdef SAMPLE_WRITE
if(input != INPUT_DUMMY) {
fwrite(buffer, 1, blocksize, fp1);
#ifdef SAMPLE_SYNC
if(c % mbinblocks == 0) { // fflush and sync (EXFAT)
fflush(fp1);
sync();
}
#endif
} // end of if(input != INPUT_DUMMY
#endif
} // end of for(c = 0; c < clim; c++
#ifdef SAMPLE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fflush(fp1); // fflush and sync (EXFAT)
sync();
fclose(fp1);
} else { // if((fp1=fopen
fprintf(stderr,"%s:", procname);
fprintf(stderr," sample: cannot open file");
fprintf(stderr,", filename: %s", filename);
fprintf(stderr,"\n");
exit(2);
}
// remove last status line
stat_line_cursor_remove();
stat_line_begin();
stat_line_printf("\rwrote ");
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf(", ");
if(secondsnow - secondsstart >= 1.0)
stat_line_readable((unsigned long)((double)c * blocksize / (secondsnow - secondsstart)) );
else
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf("/sec");
stat_line_printf(", done!");
stat_line_end();
stat_line_cursor_remove();
fprintf(stdout,"\n");
fflush(stdout);
#ifdef SAMPLE_HASH
unsigned char filename2[138];
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,"%s: sample: hashing file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,", hashfilename:%s", filename2);
fprintf(stderr,", sha256:%s\n", hashstring);
if((fp1 = fopen(filename2, "a")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
fprintf(stderr,"%s: sample: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
sprintf(command,"sha256sum %s", filename);
system(command);
#endif
signal(SIGINT, oldhandler);
free(buffer);
if(dieharder) { // randomness analysis
sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder", filename, filename);
fprintf(stderr,"%s: dieharder: running dieharder \"%s\"\n", procname, command);
system(command);
exit(0);
}
}
int help = 0;
//
// utf8 functions
//
static int utf8characters(unsigned char *buf)
{
int characters;
unsigned char *p;
p = buf;
characters = 0;
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) // first utf8 byte
characters++;
p++;
}
return(characters);
}
#define aDEBUG29 2
int utf8lengths(unsigned char *buf)
{
int lengths, len, first = 1;
unsigned char *p;
#ifdef DEBUG29
fprintf(stdout,"digits %s", buf);
fprintf(stdout,"\nlengths ");
#endif
p = buf;
len = 0;
lengths = -1;
first = 1;
while(*p != '\0') {
if(!first &&
(*p < 0x80 || // ascii char
*p > 0xbf)) { // first utf8 byte
#ifdef DEBUG29
fprintf(stdout,"%d", len);
#endif
if(lengths == -1)
lengths = len;
else if(lengths != len)
lengths = 0;
len = 0;
}
p++;
len++;
first = 0;
}
#ifdef DEBUG29
fprintf(stdout,"%d", len);
#endif
if(lengths == -1)
lengths = len;
else if(lengths != len)
lengths = 0;
#ifdef DEBUG29
fprintf(stdout,"\nlengths %d\n\n", lengths);
#endif
return(lengths);
}
#define aDEBUG42 2
static void codetoutf8(unsigned char *buf2, unsigned long code)
{
unsigned char *buf;
buf = buf2;
if(code <= 0x7f) {
*buf++ = code;
} else if(code <= 0x7ff) { // 110xxxxx 10xxxxxx
*buf++ = (0xc0 | ((code >> 6) & 0x1f));
*buf++ = (0x80 | (code & 0x3f));
} else if(code <= 0xffff) { // 1110xxxx 10xxxxxx 10xxxxxx
*buf++ = (0xe0 | ((code >> 12) & 0x0f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | (code & 0x3f));
} else if(code <= 0x10ffff) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*buf++ = (0xf0 | ((code >> 18) & 0x07));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x3ffffff) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xf8 | ((code >> 24) & 0x03));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x7fffffff) { // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xfc | ((code >> 30) & 0x01));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0xfffffffff) { // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xfe);
*buf++ = (0x80 | ((code >> 30) & 0x3f));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x3ffffffffff) { // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xff);
*buf++ = (0x80 | ((code >> 36) & 0x3f));
*buf++ = (0x80 | ((code >> 30) & 0x3f));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
}
*buf = '\0';
#ifdef DEBUG42
int c, print;
fprintf(stdout,"codepoint: %lx", code);
fprintf(stdout,", bin:");
print = 0;
for(c = (sizeof(code) * 8) - 1; c >= 0; c--) {
int bit = (code >> c) & 1;
if(bit != 0)
print = 1;
if(print) {
fprintf(stdout,"%d", bit);
if(c > 0 && c % 8 == 0)
fprintf(stdout,"|");
}
}
fprintf(stdout,", oct:");
print = 0;
fprintf(stdout,"%lo", code);
fprintf(stdout,", utf8: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout,"%02x", buf2[c]);
}
fprintf(stdout,", bin: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
if(c > 0)
fprintf(stdout,"|");
for(int d = 7; d >= 0; d--) {
fprintf(stdout,"%d", buf2[c] >> d & 1);
}
}
fprintf(stdout,", oct:");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout," %3o", buf2[c]);
}
fprintf(stdout,", character: %s", buf2);
fprintf(stdout,"\n");
#endif
}
#ifdef NOTUSED
#define aDEBUG43 2
static void utf8tocode(unsigned long *code, unsigned char *buf2)
{
unsigned char *buf;
*code = 0;
buf = buf2;
if(*buf <= 0x7f) { // 0xxxxxxx
*code = *buf;
} else if(*buf < 0xc0) { // 110xxxxx 10xxxxxx
*code = 0;
} else if(*buf < 0xe0) { // 110xxxxx 10xxxxxx
*code = *buf++ & 0x1f;
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xf0) { // 1110xxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x0f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf<0xf8) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x07;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xfc) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x03;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xfe) { // 1111110x 10xxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x01;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xff) { // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
buf++;
*code = *buf++ & 0x3f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf == 0xff) { // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
buf++;
*code = *buf++ & 0x3f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
}
#ifdef DEBUG43
int c;
fprintf(stdout, "character: %s", buf2);
fprintf(stdout, ", utf8: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout,"%02x", buf2[c]);
}
fprintf(stdout, ", bin: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
if(c > 0)
fprintf(stdout, "|");
for(int d = 7; d >= 0; d--)
fprintf(stdout, "%d", buf2[c] >> d & 1);
}
fprintf(stdout, ", oct:");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout, " %3o", buf2[c]);
}
fprintf(stdout, ", codepoint: %lx", *code);
fprintf(stdout, ", bin:");
int print = 0;
for(c = (sizeof(code) * 8) - 1; c >= 0; c--) {
int bit = (*code >> c) & 1;
if(bit != 0)
print = 1;
if(print) {
fprintf(stdout, "%d", bit);
if(c > 0 && c % 8 == 0)
fprintf(stdout, "|");
}
}
fprintf(stdout, ", oct:");
fprintf(stdout, "%lo", *code);
fprintf(stdout, "\n");
#endif
}
#endif
int characterlengths = 0; // 0 multiple lengths, x lengths are same
#define aDEBUG30 2
static void utf8getcharacter(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
if(characterlengths != 0)
p += characterlengths * n;
else {
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 DEBUG30
fprintf(stdout,"%s: utf8getcharacter:", procname);
fprintf(stdout," string: %s", string);
fprintf(stdout,", n: %d", n);
fprintf(stdout,", character: %s", buf);
fprintf(stdout,", characterlengths: %d", characterlengths);
fprintf(stdout,"\n");
#endif
}
static void utf8getcharacter1(int size, unsigned char *buf, int n, unsigned char *string)
{
unsigned char *p, *q;
p = string;
q = buf;
// find first byte of character
p += n;
// 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 DEBUG30
fprintf(stdout,"%s: utf8getcharacter:", procname);
fprintf(stdout," string: %s", string);
fprintf(stdout,", n: %d", n);
fprintf(stdout,", character: %s", buf);
fprintf(stdout,", characterlengths: %d", characterlengths);
fprintf(stdout,"\n");
#endif
}
#define aDEBUG45 2
int digitscount = 10;
// display word in "digits" base (random data)
static void out_word(int size, unsigned char *buf, unsigned char *digits, unsigned long word2) // 8.5.2021 JariK
{
int c, d, len;
unsigned long word;
unsigned char string[132], character[32];
//digitscount = utf8characters(digits);
word = word2;
len = 0;
string[0] = '\0';
if(word == 0 || digitscount < 2) {
// zero
utf8getcharacter(sizeof(character), character, 0, digits);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
} else {
// non zero
while(word > 0) {
utf8getcharacter(sizeof(character), character, word%digitscount, digits);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
word /= digitscount;
}
}
// reverse string
*buf = '\0';
len = 0;
d = utf8characters(string);
for(c = d - 1; c >= 0; c--) {
utf8getcharacter(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
}
// display word in decimal (10-base) (line number)
static void out_word_10(int size, unsigned char *buf, unsigned long word2) // 8.5.2021 JariK
{
int c, d, len;
unsigned long word;
unsigned char string[132], character[32];
unsigned char *digits10 = "0123456789";
int digitscount = 10;
//digitscount = utf8characters(digits);
word = word2;
len = 0;
string[0] = '\0';
if(word == 0 || digitscount < 2) {
// zero
utf8getcharacter1(sizeof(character), character, 0, digits10);
if(len+strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
} else {
// non zero
while(word > 0) {
utf8getcharacter1(sizeof(character), character, word % digitscount, digits10);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
word /= digitscount;
}
}
// reverse string
*buf = '\0';
len = 0;
d = utf8characters(string);
for(c = d - 1;c >= 0; c--) {
utf8getcharacter1(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 aDEBUG48 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 = utf8characters(buf);
f = utf8characters(digits);
for(c = 0; c < d; c++) {
utf8getcharacter(sizeof(character2), character2, c, buf);
ok = 0;
for(e = 0; e < f; e++) {
utf8getcharacter(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 DEBUG48
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
}
//
// lotto functions
//
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 zero = 1, sspace = 0, snewline = 0,
scrlf = 1, chars = 72, pchars = 0, charwidth = 1,
charspaces = 0, words = 0, pwords = 0,
plinesdigits = 5, slineno = 1, screen = 0,
quiet = 0, sort = 0, unique = 0,
flagdigits = 0;
#ifdef DEBUG51
static int limitsize = 0,
#endif
static unsigned long long lines = 10, plines = 0, ptotallines = 0;
static unsigned long limit, word;
static unsigned char *digits = "0123456789", character[32];
static unsigned char digitstemp[256], *digitsext = NULL;
static unsigned char linenobuf[1024];
static int print_statline = 0;
#define aDEBUG51 2
static void readword(unsigned char *buf)
{
int d,e;
unsigned char temp1024[1024];
if(limit != 0) {
word = 0;
if(zero) {
word = newressu_gen_limit(limit); // include zeroes
} else if(limit >= 1) {
while((word = newressu_gen_limit(limit)) == 0); // skip zeroes
}
#ifdef DEBUG51
if(type == 2)
fprintf(stdout, "(%0*lx)", limitsize, word);
else if(type == 8)
fprintf(stdout, "(%0*lo)", limitsize, word);
else if(type == 10)
fprintf(stdout, "(%0*lu)", limitsize, word);
else if(type == 16)
fprintf(stdout, "(%0*lx)", limitsize, word);
else {
fprintf(stdout, "(%02lu)", word);
}
#endif
out_word(sizeof(temp1024), temp1024, digits, word);
// fill leading zeroes
buf[0] = '\0';
utf8getcharacter(sizeof(character), character, 0, digits);
for(d = size - utf8characters(temp1024); d > 0; d--) {
strcat(buf, character);
}
// rest of the number
strcat(buf, temp1024);
} else if(digits != NULL) {
buf[0] = '\0';
#ifdef DEBUG51
fprintf(stdout, "(");
#endif
// fill whole word digit by digit
for(d = 0; d < size; d++) {
if(digits[0] == '0' && !zero)
e = newressu_gen_limit(digitscount - 1) + 1;
else
e = newressu_gen_limit(digitscount);
utf8getcharacter(sizeof(temp1024), temp1024, e, digits);
#ifdef DEBUG51
fprintf(stdout,"%s", temp1024);
if(charspaces == 1)
fputc(' ', stdout);
#endif
strcat(buf, temp1024);
}
#ifdef DEBUG51
fprintf(stdout, ")");
#endif
}
}
//
// stdout printing routines
//
static int line_number_length()
{
int c;
out_word_10(sizeof(linenobuf), linenobuf, lines-1);
c = strlen(linenobuf);
if(c < 5)
c = 5;
return(c);
}
static void print_line_number()
{
unsigned char linenobuf[32];
if(pwords == 0 && slineno) {
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
fprintf(stdout,"%s", linenobuf);
fprintf(stdout," ");
}
}
static int calc_spaces()
{
int spaces;
spaces = 0;
if(sspace >= 2 &&
// space between word groups
( (pwords > 0 && pwords % sspace == 0) ||
// space after linenumber
// are not printed if
// not printing linenumber
(slineno && pwords == 0) ) )
spaces++;
if(sspace &&
// space between words
( (pwords > 0) ||
// space after linenumber
(slineno && pwords == 0) ) )
spaces++;
return(spaces);
}
static void print_spaces()
{
int sp;
for(sp = calc_spaces(); sp > 0; sp--)
fprintf(stdout, " ");
}
static void print_word(unsigned char *buf)
{
int e;
if(size != 0) {
if(charspaces == 0) {
fprintf(stdout, "%s", buf);
} else {
for(e = 0; e < size; e++) {
unsigned char temp1024[1024];
utf8getcharacter(sizeof(temp1024), temp1024, e, buf);
fprintf(stdout, "%s", temp1024);
fputc(' ', stdout);
}
}
} else {
fprintf(stdout, "%s", buf);
if(charspaces == 1) {
fputc(' ', stdout);
}
}
}
#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
#define aDEBUG55 2
#define aDEBUG57 2
void digits_add_string(unsigned char **digits, char *str)
{
int digitssize;
#ifdef DEBUG55
fprintf(stdout,"\nolddigits %s", *digits);
fprintf(stdout,"\nadddigits %s", str);
#endif
digitssize = 0;
if(*digits != NULL)
digitssize += strlen(*digits);
digitssize += strlen(str);
#ifdef DEBUG57
fprintf(stdout,"digitssize:%d\n", digitssize);
fflush(stdout);
#endif
unsigned char *prevdigits = *digits;
*digits = realloc(*digits, digitssize + 1);
if(prevdigits == NULL)
**digits = '\0';
strcat(*digits, str);
#ifdef DEBUG55
fprintf(stdout,"\nnewdigits %s", *digits);
fprintf(stdout,"\n");
#endif
}
void digits_add_limits(unsigned char **digits, int start, int end)
{
int c, digitssize;
unsigned char buffer[32];
#ifdef DEBUG55
fprintf(stdout,"\nolddigits %s", *digits);
fprintf(stdout,"\nadddigits start:%d, end:%d", start, end);
#endif
digitssize = 0;
if(*digits != NULL)
digitssize += strlen(*digits);
for(c = start; c <= end; c++) {
codetoutf8(buffer, c);
digitssize += strlen(buffer);
}
#ifdef DEBUG57
fprintf(stdout,"digitssize:%d\n", digitssize);
fflush(stdout);
#endif
unsigned char *prevdigits = *digits;
*digits = realloc(*digits, digitssize + 1);
if(prevdigits == NULL)
**digits = '\0';
for(c = start; c <= end; c++) {
codetoutf8(buffer, c);
strcat(*digits, buffer);
}
#ifdef DEBUG55
fprintf(stdout,"\nnewdigits %s", *digits);
fprintf(stdout,"\n");
#endif
}
double getseconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((double)tv.tv_sec + (double)tv.tv_usec / 1000000);
}
#include <sys/ioctl.h> // for TIOCGWINSZ
#define aDEBUG50 2
#define aDEBUG71 2
void call_main(char *);
#define aCALL_MAIN 2
#ifdef CALL_MAIN
#define DEBUG99 2
int main2(int argc, char *argv[]);
void call_main(char *cmd)
{
int size, round, count, chars;
unsigned char *p, *q, *argmem,*params;
char **argv;
size = 0;
for(round = 0; round < 2; round++) {
count = 0;
p = cmd;
while(*p != '\0') {
while(*p == ' ' || *p == '\t')
p++;
q = p;
chars = 0;
while(*p != ' ' && *p != '\t' && *p != '\0') {
p++;
chars++;
}
if(round == 0) // calculate size & alloc
size += chars + 1 + sizeof(char *);
else { // move parameters to arg area
strncpy(params, q, chars);
*(argv+count) = params;
params += (chars+1);
}
count++;
}
if(round == 0) { // allocate
size += sizeof(char *); // ending NULL
argmem = malloc(size);
argv = (char **)argmem;
params = argmem + sizeof(char *) * (count+1);
}
}
*(argv+count) = NULL; // ending NULL
#ifdef DEBUG99
fprintf(stdout, "size:%d,", size);
fprintf(stdout, " argmem:");
for(int c = 0; c < size; c++) {
if(c > 0 && c % 8 == 0)
fprintf(stdout, "|");
if(*(argmem+c) == '\\')
fprintf(stdout, "\\\\");
if(isprint(*(argmem + c)))
fprintf(stdout, "%c", *(argmem + c));
else
fprintf(stdout, "\\%02x", *(argmem + c));
}
fprintf(stdout, "\n");
#endif // #ifdef DEBUG99
main2(count, argv);
}
int main(int argc, char *argv[])
{
int first;
char buffer[1024];
first = 1;
buffer[0] = '\0';
for(int c = 0; c < argc; c++) {
if(!first)
strcat(buffer, " ");
strcat(buffer, argv[c]);
first = 0;
}
#ifdef DEBUG99
fprintf(stdout,"main: cmd \"%s\"\n",buffer);
#endif
call_main(buffer);
}
#endif // #ifdef CALL_MAIN
#ifdef CALL_MAIN
int main2(int argc, char *argv[])
{
#ifdef DEBUG99
fprintf(stdout, "main2args:");
for(int c = 0; c < argc; c++) {
fprintf(stdout, " %d:\"%s\"", c, argv[c]);
}
fprintf(stdout, "\n");
#endif // #ifdef DEBUG99
#else // #ifdef CALL_MAIN
static unsigned char programfiledigest[HashLen];
int main(int argc, char *argv[])
{
#endif // #ifdef CALL_MAIN
int c, d, status = 0;
#ifdef DEBUG67
fprintf(stdout,"GENT_SIZE:%d",GENT_SIZE);
fprintf(stdout,", SAMPLE_SIZE:%d",SAMPLE_BLOCKSIZE);
fprintf(stdout,"\n");
#endif
#ifdef DEBUG31
for(c=20;c>1;c--) {
stat_line_begin();
for(d=0;d<c;d++) {
stat_line_printf("+");
}
stat_line_end();
}
#endif
procname = argv[0];
limit = 0;
newressu_file_digest("/proc/self/exe", programfiledigest);
gent_clear();
clockbytes = 0;
for(d = 0; d < 1024; d++)
periods[d] = 0;
#ifdef USE_TIMER
int timer = 0;
double timerstart;
#endif
//
// look thru command line parameters
//
for(c = 1; c < argc; c++) {
if(!strncmp("-", argv[c], 1)) {
if(!strcmp("--lineno", argv[c])) {
slineno = !slineno; // print line number
} else if(!strcmp("--crlf", argv[c])) {
scrlf = !scrlf;
slineno = 0;
} else if(!strcmp("--quiet", argv[c])) {
quiet = !quiet;
} else if(!strcmp("--digits", argv[c])) {
flagdigits = !flagdigits;
} 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; // print line number
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) > 0) {
snewline = atoi(argv[c] + 9);
} else if(c + 1 < argc && atoi(argv[c + 1]) > 0) {
snewline = atoi(argv[c + 1]);
c++;
}
} 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(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--blocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
blocksize = getlonglong(argv[c] + 11);
} else if(c + 1 < argc) {
blocksize = getlonglong(argv[c + 1]);
c++;
}
blocksize_set = 1;
} else if(!strncmp("--blocks", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
blocks = getlonglong(argv[c] + 8);
} else if(c + 1 < argc) {
blocks = getlonglong(argv[c + 1]);
c++;
}
blocks_set = 1;
} else if(!strcmp("--dieharder", argv[c])) {
dieharder = !dieharder;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
newressu_version();
#ifdef SHA256
fprintf(stderr,"\nsha256(");
for(int c = 0; c < HashLen; c++) {
fprintf(stderr, "%02x", programfiledigest[c]);
}
#endif
fprintf(stderr, ")\n\n");
help = 1;
} else if(!strcmp("--webversion", argv[c])) {
fprintf(stderr, "%s", programname); // touch these outside MAIN
fprintf(stderr,", sha256(");
for(int c = 0; c < HashLen; c++) {
fprintf(stderr, "%02x", programfiledigest[c]);
}
fprintf(stderr,")\n");
exit(0);
} 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++;
}
//fprintf(stdout,"limit:%lu, %ld bytes\n", limit, sizeof(limit));
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
} else if(!strncmp("--bits", argv[c], 6)) {
if(*(argv[c] + 6) != '\0') {
ressut_bits1_needed = atoi(argv[c] + 6);
} else if(c + 1 < argc) {
ressut_bits1_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;
screen = 0;
} else if(!strncmp("-c*", argv[c], 3)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
words = 0;
#ifdef DEBUG71
fprintf(stdout,"screencolumns:%d\n", chars);
#endif
} else if(!strncmp("-l*", argv[c], 3)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
lines = w.ws_row-1;
#ifdef DEBUG71
fprintf(stdout,"screenlines:%lld\n", lines);
#endif
} else if(!strncmp("--screen", argv[c],8)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
lines = w.ws_row-1;
words = 0;
screen = 1;
#ifdef DEBUG71
fprintf(stdout,"screencolumns:%d", chars);
fprintf(stdout,", screenlines:%lld\n", lines);
#endif
} 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++;
}
if(chars < 1)
chars = 72;
words = 0;
screen = 0;
} else if(!strncmp("-l",argv[c], 2)) { // lines
if(*(argv[c] + 2) != '\0') {
lines = atoll(argv[c] + 2);
} else if(c + 1 < argc) {
lines = atoll(argv[c + 1]);
c++;
}
screen = 0;
} else if(!strcmp("-b", argv[c]) ||
!strcmp("--bin", argv[c]) ||
!strcmp("--1bit", argv[c]) ||
!strcmp("--1bits", argv[c])) {
digits = "01";
charspaces = 0;
charwidth = 1;
size = 8;
type = 2;
} else if(!strcmp("--2bits", argv[c])) {
digits = "0123";
charspaces = 0;
charwidth = 1;
size = 8;
type = 2;
} else if(!strcmp("-o", argv[c]) ||
!strcmp("--oct", argv[c]) ||
!strcmp("--3bits", argv[c]) ) {
digits = "01234567";
charspaces = 0;
charwidth = 1;
size = 3;
type = 8;
} else if(!strcmp("-d", argv[c]) ||
!strcmp("--dec", argv[c])) {
digits = "0123456789";
charspaces = 0;
charwidth = 1;
size = 5;
type = 10;
} else if(!strcmp("-x", argv[c]) ||
!strcmp("--hex", argv[c]) ||
!strcmp("--4bits", argv[c])) {
digits = "0123456789abcdef";
charspaces = 0;
charwidth = 1;
size = 4;
type = 16;
} else if(!strcmp("-X", argv[c]) ||
!strcmp("--HEX", argv[c]) ||
!strcmp("--4BITS", argv[c])) {
digits = "0123456789ABCDEF";
charspaces = 0;
charwidth = 1;
size = 4;
type = 16;
} else if(!strcmp("-1", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-11", argv[c])) {
digits =
"0123456789";
charspaces = 0;
charwidth = 1;
size = 1;
type = 10;
} else if(!strcmp("-12", argv[c])) {
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
charspaces = 0;
charwidth = 1;
size = 1;
} else if(!strcmp("-13", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-13v1", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz" \
"aeiouy";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-13v2", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz" \
"aeiouy" \
"aeiouy";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-13v3", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz" \
"aeiouy" \
"aeiouy" \
"aeiouy";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-13v4", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz" \
"aeiouy" \
"aeiouy" \
"aeiouy" \
"aeiouy";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("-2", argv[c]) ||
!strcmp("--6bits", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"_-"; // 6 bits
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("-3", argv[c])) { // 9.5.2021 JariK
digits =
"!\"#$%&'()*+,-./0123456789:;<=>?@" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
"abcdefghijklmnopqrstuvwxyz{|}~";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("-5", argv[c]) ||
!strcmp("--5bits", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUV"; // 5 bits
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("-9", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--dnk", argv[c]) || // Danish alphabet
!strcmp("--nor", argv[c])) { // Norwegian alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" \
"abcdefghijklmnopqrstuvwxyzæøå";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--fin", argv[c]) || // Finnish alphabet
!strcmp("--swe", argv[c])) { // Swedish alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ" \
"abcdefghijklmnopqrstuvwxyzåäö";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--rus", argv[c])) { // Russian alphabet
digits =
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ" \
"абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--est", argv[c])) { // Estonian alphabet
digits =
"ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY" \
"abcdefghijklmnopqrsšzžtuvwõäöüxy";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--ltu", argv[c])) { // Lithuanian alphabet
digits =
"AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ" \
"aąbcčdeęėfghiįyjklmnoprsštuųūvzž";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} 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ž";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} 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
||!strcmp("--eng", argv[c]) // English alphabet
) {
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--deu", argv[c])) { // Deutsch alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ" \
"abcdefghijklmnopqrstuvwxyzäöüß";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--grc", argv[c])) { // Greek alphabet
digits =
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" \
"αβγδεζηθικλμνξοπρστυφχψω";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--jp", argv[c])) { // all Japanese alphabets
digits = NULL;
digits_add_string(&digits,
"ぁあぃいぅうぇえぉおかがきぎく"
"ぐけげこごさざしじすずせぜそぞた"
"だちぢっつづてでとどなにぬねのは"
"ばぱひびぴふぶぷへべぺほぼぽまみ"
"むめもゃやゅゆょよらりるれろゎわ"
"ゐゑをんゔゕゖ");
digits_add_string(&digits,
"゠ァアィイゥウェエォオカガキギク"
"グケゲコゴサザシジスズセゼソゾタ"
"ダチヂッツヅテデトドナニヌネノハ"
"バパヒビピフブプヘベペホボポマミ"
"ムメモャヤュユョヨラリルレロヮワ"
"ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ");
digits_add_limits(&digits, 0x4e00, 0x9fef);
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--jp1", argv[c]) // Japanese hiragana alphabet
|| !strcmp("--hir", argv[c])) { // Japanese hiragana alphabet
digits =
"ぁあぃいぅうぇえぉおかがきぎく"
"ぐけげこごさざしじすずせぜそぞた"
"だちぢっつづてでとどなにぬねのは"
"ばぱひびぴふぶぷへべぺほぼぽまみ"
"むめもゃやゅゆょよらりるれろゎわ"
"ゐゑをんゔゕゖ";
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--jp2", argv[c]) // Japanese katakana alphabet
|| !strcmp("--kat", argv[c])) { // Japanese katakana alphabet
digits =
"゠ァアィイゥウェエォオカガキギク"
"グケゲコゴサザシジスズセゼソゾタ"
"ダチヂッツヅテデトドナニヌネノハ"
"バパヒビピフブプヘベペホボポマミ"
"ムメモャヤュユョヨラリルレロヮワ"
"ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ";
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--cn", argv[c]) // Chinese alphabet
|| !strcmp("--jp3", argv[c]) // Japanese kanji alphabet
|| !strcmp("--kan", argv[c])) { // Japanese kanji alphabet
digits = NULL;
digits_add_limits(&digits, 0x4e00, 0x9fef);
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--kor", argv[c])) { // Korean alphabet
digits = NULL;
digits_add_limits(&digits,0xac00,0xd7a3); // Hangul Syllables (AC00–D7A3)
//digits_add_limits(&digits,0x1100,0x11ff); // Hangul Jamo (1100–11FF)
//digits_add_limits(&digits,0x3130,0x318f); // Hangul Compatibility Jamo (3130–318F)
//digits_add_limits(&digits,0xa960,0xa97f); // Hangul Jamo Extended-A (A960–A97F)
//digits_add_limits(&digits,0xd7b0,0xd7ff); //Hangul Jamo Extended-B (D7B0–D7FF)
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--ind", argv[c])
|| !strcmp("--hin", argv[c])) { // Hindi alphabet
digits="ँंःअआइईउऊऋएऐऑओऔकखगघचछजझञटठडढणतथदधनपफबभमयरलवशषसह़ािीुूृॅेैॉोौ्ाकेरहसनींमि्तपलोयैबदवुजएगचथअऔूउशडख़भआटछधफइँषघईझठौणॉओृढऊऐऑञःॅऋ";
/*
digits =
"ँंःअआइईउऊऋएऐऑओऔक"
"खगघचछजझञटठडढणतथद"
"धनपफबभमयरलवशषसह़ा"
"िीुूृॅेैॉोौ्ाकेरह"
"सनींमि्तपलोयैबदवुजए"
"गचथअऔूउशडख़भआटछधफइँ"
"षघईझठौणॉओृढऊऐऑञःॅ"
"ऋ";
*/
//digits = NULL;
//digits_add_limits(&digits,0x900,0x97f); // Hindi (0900-097f)
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--got", argv[c])) { // Gothic alphabet
digits=
"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷𐌸𐌹𐌺𐌻𐌼𐌽𐌾𐌿"
"𐍀𐍁𐍂𐍃𐍄𐍅𐍆𐍇𐍈𐍉𐍊";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--cards", argv[c])) {
digits=
"🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂭🂮" \
"🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂽🂾" \
"🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃍🃎" \
"🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃝🃞";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--cardsuits", argv[c])) {
digits=
"♠♡♢♣♤♥♦♧";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--chessmen", argv[c])) {
digits=
"♔♕♖♗♘♙♚♛♜♝♞♟";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--dice", argv[c])) {
digits=
"⚀⚁⚂⚃⚄⚅";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--mahjong", argv[c])) {
digits= // removed 🀄 & 🀫
"🀀🀁🀂🀃🀅🀆" \
"🀇🀈🀉🀊🀋🀌🀍🀎🀏" \
"🀐🀑🀒🀓🀔🀕🀖🀗🀘" \
"🀙🀚🀛🀜🀝🀞🀟🀠🀡" \
"🀢🀣🀤🀥🀦🀧🀨🀩🀪";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--dna", argv[c])) {
digits=
"acgt";
charspaces = 0;
charwidth = 1;
size = 4;
type = 0;
} else if(!strcmp("--DNA", argv[c])) {
digits=
"ACGT";
charspaces = 0;
charwidth = 1;
size = 4;
type = 0;
} else if(!strcmp("--pattern1", argv[c])) {
digits=
"▌▙▄";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern2", argv[c])) {
digits=
"◜◝◞◟";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern3", argv[c])) {
digits=
"\\/";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern4", argv[c])) {
digits=
"◸◹◺◿";
charspaces = 1;
charwidth = 2;
size = 1;
type = 0;
} else if(!strcmp("--pattern5", argv[c])) {
digits=
"▧▨";
charspaces = 1;
charwidth = 2;
size = 1;
type = 0;
} 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;
type = 0;
} 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 || utf8characters(digits) < 2) {
fprintf(stderr,"%s: not enough digits \"%s\"\n", procname, argv[c]);
help = 1;
}
size = 1;
#ifdef USE_TIMER
} else if(!strcmp("--timer", argv[c])) {
timer = 1;
#endif
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
} else if(!strcmp("--pseudoressu", argv[c])) {
input = INPUT_PSEUDORESSU;
} else if(!strcmp("--fast", argv[c])
|| !strcmp("--fastressu", argv[c]) ) {
input = INPUT_FASTRESSU;
} else if(!strcmp("--single", argv[c])
|| !strcmp("--singleressu", argv[c]) ) {
input = INPUT_SINGLERESSU;
} else if(!strncmp("--fixedclock", argv[c], 12)) {
if(*(argv[c] + 12) != '\0' && atoi(argv[c] + 12) > 1) {
fixedclockchainlength = atoi(argv[c] + 12);
clockmode = 1;
} else if(c + 1 < argc && atoi(argv[c + 1]) > 1) {
fixedclockchainlength = atoi(argv[c + 1]);
clockmode = 1;
c++;
} else {
clockmode = !clockmode;
}
if(fixedclockchainlength < 5 ||
fixedclockchainlength > 255)
fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
ressu_setclock(clockmode);
} else if(!strcmp("--verbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--statline", argv[c])) {
print_statline = !print_statline;
#ifdef FORT
} else if(!strcmp("--fort", argv[c])) {
input = INPUT_FORT;
} else if(!strcmp("--fortxor", argv[c])) {
input = INPUT_FORTXOR;
} else if(!strcmp("--fortverbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--fortuseweb", argv[c])) {
fort_use_web = !fort_use_web;
#endif
#ifdef USE_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
#endif
#ifdef USE_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
#endif
} else if(!strcmp("--urandom", argv[c])) {
input = INPUT_URANDOM;
#ifdef USE_RANDOM
} else if(!strcmp("--random", argv[c])) {
input = INPUT_RANDOM;
#endif
} else if(!strcmp("--dummy", argv[c])) {
input = INPUT_DUMMY;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
status = 1;
help = 1;
}
} else {
help = 1;
} // if(!strncmp
} // for(c = 0
if(size == 0)
size = 1;
else if(size > 1024)
size = 1024;
if(lines < 1)
lines = 1;
#ifdef USE_TIMER
timerstart = getseconds();
#endif
digitscount = utf8characters(digits);
characterlengths = utf8lengths(digits);
#ifdef FORT
if(input == INPUT_FORT ||
input == INPUT_FORTXOR ) {
strcpy(fort_random_file, "newressufort.rnd");
strcpy(fort_secret_file, "newressufortsecret.rnd");
//fort_verbose = 0;
fort_init();
}
#endif
if(dieharder && !sample) {
fprintf(stderr,"%s: cannot --dieharder without --sample\n", procname);
exit(2);
}
if((filesize_set || blocksize_set || blocks_set) && !sample) {
fprintf(stderr,"%s: cannot --filesize, --blocks or --blocksize without --sample\n", procname);
exit(2);
}
if(sample) { // & dieharder
dump_sample();
exit(status);
} // if(sample)
if(flagdigits) {
int count = 0;
unsigned char *p;
fprintf(stdout,"digits:");
p = digits;
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) { // first utf8 byte
count++;
if((charwidth == 2 && count >= 32) ||
(charwidth == 1 && count >= 72) )
break;
}
fprintf(stdout,"%c", *p);
p++;
}
if(*p != '\0')
fprintf(stdout,"...");
fprintf(stdout,"\n");
}
// 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 = utf8characters(wordbuf);
}
pchars = 0;
pwords = 0;
int linew = 0;
// in beginning of line, count printed line number
if(!quiet && slineno) {
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
pchars += strlen(linenobuf);
pchars++;
}
// count words
while((chars > 0 && pchars + size * charwidth + calc_spaces() <= chars) ||
(words > 0 && pwords < words)) {
linew++;
#ifdef DEBUG50
fprintf(stdout,"spaces:%d", calc_spaces());
#endif
pchars += calc_spaces();
pchars += (size*charwidth);
pwords++;
#ifdef DEBUG50
fprintf(stdout,", chars:%d", chars);
fprintf(stdout,", pchars:%d", pchars);
fprintf(stdout,", words:%d", words);
fprintf(stdout,", pwords:%d", pwords);
fprintf(stdout,"\n");
#endif
}
// one data word needed
if(linew < 1)
linew = 1;
#define aDEBUG89 2
unsigned long wordvalues=1, wordvaluesold;
for(c = 0; c < size; c++) {
wordvaluesold = wordvalues;
wordvalues *= digitscount;
#ifdef DEBUG89
fprintf(stdout, "wordvaluesold:%ld", wordvaluesold);
fprintf(stdout, ", digitscount:%d", digitscount);
fprintf(stdout, ", wordvalues:%ld", wordvalues);
fprintf(stdout, "\n");
#endif
if(wordvalues / digitscount != wordvaluesold) {
wordvalues = 0;
#ifdef DEBUG89
fprintf(stdout, "wordvalues:%ld", wordvalues);
fprintf(stdout, "\n");
#endif
break;
}
}
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)", digitscount, wordvalues);
fprintf(stderr, ", words:%d\n", linew);
help = 1;
lines = 0;
}
}
// "small" words as single newressu_gen_limit() call
if(limit == 0 && wordvalues > 0)
limit = wordvalues;
#ifdef DEBUG51
unsigned char buffer10[10];
if(type == 2)
sprintf(buffer10, "%2lx", limit - 1);
else if(type == 8)
sprintf(buffer10, "%2lo", limit - 1);
else if(type == 10)
sprintf(buffer10, "%2ld", limit - 1);
else if(type == 16)
sprintf(buffer10, "%2lx", limit - 1);
else
sprintf(buffer10, "%2ld", limit - 1);
limitsize = strlen(buffer10);
#endif
if(stats) {
fprintf(stderr, "randomsource: %s", randomgen[input]);
fprintf(stderr, ", clockmode: %d", clockmode);
if(clockmode==1)
fprintf(stderr, ", clockchainlength: %d", fixedclockchainlength);
fprintf(stderr, ", size: %d", size);
fprintf(stderr, ", lines: %llu", lines);
fprintf(stderr, ", linew: %d", linew);
fprintf(stderr, ", pchars: %d", pchars);
fprintf(stderr, ", pwords: %d", pwords);
fprintf(stderr, ", tchars: %llu", (unsigned long long)size * linew * lines);
fprintf(stderr, ", digitscount: %d", digitscount);
if(wordvalues > 0)
fprintf(stderr, ", wordvalues: %lu", wordvalues);
if(limit > 0) {
fprintf(stderr, ", limit: %lu", limit);
#ifdef DEBUG51
fprintf(stderr, ", type: %d", type);
fprintf(stderr, ", limitsize%d: %d", type, limitsize);
#endif
}
fprintf(stderr, "\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 --rand", "print numbers in rand style listing" },
{ "newressu --space 2", "print numbers in 2 number groups" },
{ "newressu --newline 5", "print numbers in 5 line groups" },
{ "newressu -l*", "fill all screen lines" },
{ "newressu -c*", "fill all screen columns" },
{ "newressu --screen", "fill screen columns and lines" },
{ "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 --isupper --limBAAAAA","print five letter uppercase words" },
{ "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 --dnk/--nor", "danish/norwegian alphabet" },
{ "newressu --fin/--swe", "finnish/norwegian alphabet" },
{ "newressu --rus", "russian alphabet" },
{ "newressu --est", "estonian alphabet" },
{ "newressu --ltu", "lithuanian alphabet" },
{ "newressu --lva", "latvian alphabet" },
{ "newressu --fra/--gbr/--usa/--ita", "french/gb/us/italian alphabet" },
{ "newressu --deu", "deutsch alphabet" },
{ "newressu --grc", "greek alphabet" },
{ "newressu --jp", "japan alphabet (hiragana, katakana, kanji) " },
{ "newressu --jp1/--hir", "japan alphabet (hiragana) " },
{ "newressu --jp2/--kat", "japan alphabet (katakana) " },
{ "newressu --jp3/--kan", "japan alphabet (kanji) " },
{ "newressu --cn", "chinese alphabet" },
{ "newressu --kor", "korean alphabet" },
{ "newressu --got", "gothic alphabet" },
{ "newressu --cards", "playing cards" },
{ "newressu --cardsuits", "playing card suits" },
{ "newressu --chessmen", "chess men" },
{ "newressu --dice", "print dice" },
{ "newressu --mahjong", "print mahjong pieces" },
{ "newressu -i▌▙▄ / --pattern1", "print pattern1" },
{ "newressu -i◜◝◞◟ / --pattern2", "print pattern2" },
{ "newressu -i\\\\/ / --pattern3", "print pattern2" },
{ "newressu -i▧▨ / --pattern5", "print pattern2" },
{ "newressu --ressu", "use randomness from ressu (default)" },
{ "newressu --pseudoressu", "use randomness from pseudo random ressu" },
{ "newressu --fast/--fastressu", "use randomness from fast ressu" },
{ "newressu --single/--singleressu", "use randomness from single round of ressu" },
#ifdef FORT
{ "newressu --fort", "use randomness from fort" },
#endif
#ifdef USE_RDRAND
{ "newressu --rdrand", "use randomness from intel rdrand" },
#endif
#ifdef USE_RDSEED
{ "newressu --rdseed", "use randomness from intel rdseed" },
#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(stderr, "*");
fprintf(stderr, "\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) { // no sort, no lotto
pwords = 0;
while(pwords < linew) {
readword(wordbuf);
if(!quiet) {
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
newressu_output = 1;
}
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) {
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
newressu_output = 1;
}
pwords++;
} // while(pwords<linew) {
} // if(!sort)
if(!quiet) {
fprintf(stdout, "\n");
}
plines++;
ptotallines++;
// print empty line
if(!quiet &&
snewline > 0 &&
plines%snewline == 0) {
// if screenfull printed, use
// total lines (contains also
// empty lines), if not
// screenfull use printed
// lines (without empty lines)
if((screen && ptotallines < lines) ||
(!screen && plines < lines)) {
fprintf(stdout, "\n");
ptotallines++;
}
}
//fflush(stdout);
newressu_output = 0;
// all needed lines printed?
if(screen && snewline > 0 &&
ptotallines >= lines)
break;
if(plines >= lines)
break;
#define STATDIV (1024*1024*100)
if(print_statline) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
print_statline = 0;
} else {
if(lines % 1000 == 0) {
unsigned char buf10[10];
unsigned long long bytes;
int pros = (int)(((double)plines/lines)*100);
bytes = (((unsigned long long)size * linew * plines) / STATDIV) * STATDIV;
stat_line_get_readable(buf10, bytes);
#ifdef DEBUG97
fprintf(stderr, "%lld", (unsigned long long)size * linew * plines);
fprintf(stderr, ", %lld", bytes);
fprintf(stderr, ", %s", buf10);
fprintf(stderr, "\n");
#endif
stat_line_begin();
stat_line_printf("%s characters written:", randomgen[input]);
stat_line_readable((unsigned long) size * linew * plines);
stat_line_printf(", %d%%", pros);
//stat_line_printf(", lines:%lld",lines);
//stat_line_printf(", plines:%lld",plines);
stat_line_end();
}
stat_line_cursor();
}
} // if(print_statline)
} // for(;;)
if(print_statline) { // 0=stdin, 1=stdout, 2=stderr
stat_line_begin();
stat_line_end();
stat_line_cursor_remove();
}
#ifdef USE_TIMER
if(timer) {
double timertook=getseconds()-timerstart;
fprintf(stderr, "run time %f seconds", timertook);
fprintf(stderr, ", %lld lines", plines);
fprintf(stderr, ", %f useconds/line", timertook * 1000000 / plines);
fprintf(stderr, ", %d characters/line", pwords * size);
fprintf(stderr, ", %f useconds/character",
(timertook * 1000000 / plines) / (pwords * size) );
fprintf(stderr, "\n");
}
#endif
fflush(stdout);
if(digitsext != NULL)
free(digitsext);
#ifdef FORT
if(input == INPUT_FORT ||
input == INPUT_FORTXOR) {
fort_save();
}
#endif
exit(status);
}
#endif // MAIN
newressu.h
void ressu_genbytes(int size, unsigned char *buffer);
unsigned long ressu_gen_limit(unsigned long limit);
void pseudoressu_bytes(int buflen, unsigned char *buf);
void inccvar();
void clearcvar();
#define INPUT_RESSU 0
#define INPUT_PSEUDORESSU 1
#define INPUT_FAST 2
#define INPUT_SINGLE 3
#define INPUT_FORT 6
#define INPUT_FORTXOR 7
#define INPUT_RDRAND 8
#define INPUT_RDSEED 9
#define INPUT_URANDOM 10
#define INPUT_RANDOM 11
extern int verbose;
extern int input;
extern int newressu_output;
extern char *randomgen[];
extern void pseudoressu_bytes(int, unsigned char *);
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"
extern unsigned char *procname;
static unsigned char *programname = "fort version 0.52 ©";
unsigned char *fortuseragent = "fort version 0.52 ©";
static unsigned char *copyright = "Copyright (c) 2020-2022 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_use_web = 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;
#define FORT_USE_WEB 2
#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
// Additional secrets to fort
// (Adversary must guess these too)
#define ADDITIONAL_SECRETS 2
#ifdef ADDITIONAL_SECRETS
unsigned char fort_secret_file[128] = "fortsecret.rnd";
unsigned char *program_secret = "OHUwiVmwm8HlqNhKxPi9rdt_8lm4jXI8hi-FCntPAQN_UXOyt4s6zQnRo__ySAd1";
#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();
void hash_update_cvar(HashCtx *hash)
{
hash_update(hash, (unsigned char *)&cvar,
cvarsize + 1);
inccvar();
}
#define aDEBUG8 2
void hash_update_ressu(HashCtx *hash)
{
unsigned char temp[16];
ressu_genbytes(sizeof(temp), temp);
#ifdef DEBUG8
fprintf(stdout,", ressu:");
for(int c = 0; c < sizeof(temp); c++)
fprintf(stdout,"%02x", temp[c]);
#endif
hash_update(hash, temp, sizeof(temp));
}
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;
}
}
#define aDEBUG18 2
void hash_init(HashCtx *hash)
{
FORT_INTERNAL_EVENTS_START(10)
HashInit(hash);
#ifdef DEBUG18
fprintf(stdout,"init\n");
#endif
FORT_INTERNAL_EVENTS_END(11)
}
void hash_update(HashCtx *hash, unsigned char *data, int len)
{
FORT_INTERNAL_EVENTS_START(12)
HashUpdate(hash, data, len);
#ifdef DEBUG18
fprintf(stdout,"update ");
for(int d = 0; d < len; d++)
fprintf(stdout,"%02x",data[d]);
fprintf(stdout,"\n");
#endif
FORT_INTERNAL_EVENTS_END(13)
}
void hash_final(unsigned char digest[HashLen], HashCtx *hash)
{
FORT_INTERNAL_EVENTS_START(14)
HashFinal(digest, hash);
#ifdef DEBUG18
fprintf(stdout,"final ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
FORT_INTERNAL_EVENTS_END(15)
}
static unsigned char fort_key[HashLen];
void fort_rekey(unsigned char *digest)
{
HashCtx hash;
FORT_INTERNAL_EVENTS_START(16)
hash_init(&hash);
hash_update(&hash, fort_key, sizeof(fort_key));
hash_update_cvar(&hash);
hash_final(digest, &hash);
// Forget hash
memset(&hash, 0, sizeof(hash));
FORT_INTERNAL_EVENTS_END(17)
}
#define FORT_PSEUDO_LIMIT 1048576
// use
// $ ./newressu --fort -x -w32 -s2 -l2000 --space | more
// to debug...
// 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 fort_save();
static char current_timezone[10];
#define aDEBUG22 2
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_cvar(&hash);
hash_update(&hash, buf, len);
#ifdef DEBUG22
fprintf(stdout,"\nprevkey ");
for(int d = 0; d < sizeof(fort_key); d++)
fprintf(stdout,"%02x", fort_key[d]);
fprintf(stdout,"\ncvar ");
for(int d = 0; d < cvarsize + 1; d++)
fprintf(stdout,"%02x", cvar[d]);
fprintf(stdout,"\ndata ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", buf[d]);
fprintf(stdout,"\ndata asc ");
for(int d = 0; d < len; d++) {
if(isprint(buf[d]))
fprintf(stdout,"%c", buf[d]);
else
fprintf(stdout,"\\%02x", buf[d]);
}
#endif
hash_final(fort_key, &hash);
#ifdef DEBUG22
fprintf(stdout,"\nnewkey ");
for(int d = 0; d < sizeof(fort_key); d++)
fprintf(stdout,"%02x", fort_key[d]);
fprintf(stdout,"\n");
#endif
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)
}
static FORT_COUNTER fort_reseed_count = 0;
static IUTIME fort_next_reseed = 0;
#define aDEBUG28 2
#ifdef FORT_ORIGINAL_VERSION
void fort_pseudo_random_data(int len,
unsigned char *buf)
{
unsigned char digest[HashLen];
unsigned int n, blockbytes;
#ifdef DEBUG28
int d = 0;
#endif
FORT_INTERNAL_EVENTS_START(18)
blockbytes = 0;
while(len != 0) {
FORT_INTERNAL_EVENTS_START(19)
fort_rekey(digest);
n = (len < HashLen) ? len : HashLen;
#ifdef DEBUG28
fprintf(stdout,"\nbuf(%02x): ",d++);
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",buf[c]);
fprintf(stdout,"\ndigest: ");
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",digest[c]);
fprintf(stdout,"\nsum: ");
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",buf[c]^digest[c]);
fprintf(stdout,"\n");
#endif // #ifdef DEBUG18
memcpy(buf, digest, 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(digest, 0, sizeof(digest));
FORT_INTERNAL_EVENTS_END(21)
}
#define aDEBUG34 2
void fort_random_data(int len, unsigned char *buf)
{
int c;
IUTIME tenths;
HashCtx hash;
unsigned char digest[HashLen];
FORT_INTERNAL_EVENTS_START(24)
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(digest, &fort_pools[c].pool);
#ifdef DEBUG34
fprintf(stdout,"\ndata %2d ",c);
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x",digest[d]);
#endif
hash_update(&hash, digest, sizeof(digest));
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
// save earlier pool to new one
hash_update(&fort_pools[c].pool,
digest, sizeof(digest));
c++;
FORT_INTERNAL_EVENTS_END(26)
}
hash_update_cvar(&hash);
hash_final(digest, &hash);
#ifdef DEBUG34
fprintf(stdout,"\ndigest ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
fort_reseed(sizeof(digest), digest);
// Forget hash context
memset(&hash, 0, sizeof(hash));
// Forget reseed key
memset(digest, 0, sizeof(digest));
}
fort_pseudo_random_data(len, buf);
FORT_INTERNAL_EVENTS_END(27)
}
#endif // #ifdef FORT_ORIGINAL_VERSION
#ifdef FORT_XOR_VERSION
void fort_pseudo_random_data_xor(int len,
unsigned char *buf)
{
unsigned char digest[HashLen];
unsigned int n, blockbytes;
#ifdef DEBUG28
int d = 0;
#endif
FORT_INTERNAL_EVENTS_START(18)
blockbytes = 0;
while(len != 0) {
FORT_INTERNAL_EVENTS_START(19)
fort_rekey(digest);
n = (len < HashLen) ? len : HashLen;
#ifdef DEBUG28
fprintf(stdout,"\nbuf(%02x): ", d++);
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", buf[c]);
fprintf(stdout,"\ndigest: ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
fprintf(stdout,"\nsum: ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", buf[c] ^ digest[c]);
fprintf(stdout,"\n");
#endif
for(int c = 0; c < n; c++)
buf[c] ^= digest[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(digest, 0, sizeof(digest));
FORT_INTERNAL_EVENTS_END(21)
}
void fort_random_data_xor(int len, unsigned char *buf)
{
int c;
IUTIME tenths;
HashCtx hash;
unsigned char digest[HashLen];
FORT_INTERNAL_EVENTS_START(24)
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(digest, &fort_pools[c].pool);
#ifdef DEBUG34
fprintf(stdout,"\ndata %2d ", c);
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
#endif
hash_update(&hash, digest, sizeof(digest));
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
// save earlier pool to new one
hash_update(&fort_pools[c].pool,
digest, sizeof(digest));
c++;
FORT_INTERNAL_EVENTS_END(26)
}
hash_update_cvar(&hash);
hash_final(digest, &hash);
#ifdef DEBUG34
fprintf(stdout,"\ndigest ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
fort_reseed(sizeof(digest), digest);
// Forget hash context
memset(&hash, 0, sizeof(hash));
// Forget reseed key
memset(digest, 0, sizeof(digest));
}
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 aDEBUG53 2
void fort_reseed_file(unsigned char *filename)
{
int c, cnt, bytes, characters;
#ifdef DEBUG53
unsigned char *p;
#endif
FILE *fp1;
unsigned char buffer[1024], digest[HashLen];
HashCtx hash;
bytes = 0;
characters = 0;
if((fp1 = fopen(filename, "r")) != NULL) {
HashInit(&hash);
while(fgets(buffer, sizeof(buffer), fp1) != NULL) {
cnt = strlen(buffer);
HashUpdate(&hash, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
#ifdef DEBUG53
p = buffer;
while(*p != '\0') {
if(*p == '\\')
fprintf(stdout, "\\\\");
else if(isprint(*p) || *p == '\n')
fputc(*p, stdout);
else
fprintf(stdout,"\\%02x", *p);
p++;
}
#endif
}
hash_update_cvar(&hash);
HashFinal(digest, &hash);
fort_reseed(sizeof(digest), digest);
fclose(fp1);
}
#ifdef DEBUG53
//if(verbose) {
fprintf(stdout,"fort_reseed_file %s", filename);
fprintf(stdout,", %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
//}
#endif
}
#define FORT_SAVE_SIZE 1024
#define aDEBUG57
void fort_save()
{
FILE *fp1;
unsigned char buffer[FORT_SAVE_SIZE];
memset(buffer, 0, sizeof(buffer));
if((fp1 = fopen(fort_random_file, "w")) != NULL) {
fort_pseudo_random_data(sizeof(buffer), buffer);
#ifdef DEBUG57
for(int c = 0; c < sizeof(buffer); c++) {
if(c % 32 == 0) {
if(c != 0)
fprintf(stdout,"\n");
fprintf(stdout,"save %05d ", c);
}
fprintf(stdout," %02x", buffer[c]);
}
fprintf(stdout,"\n");
#endif
fwrite(buffer, 1, sizeof(buffer), fp1);
memset(buffer, 0, sizeof(buffer));
fclose(fp1);
}
}
void fort_restore()
{
int d;
#ifdef DEBUG57
int random;
#endif
FILE *fp1;
unsigned char buffer[FORT_SAVE_SIZE];
memset(buffer, 0, sizeof(buffer));
if((fp1 = fopen(fort_random_file, "r"))
!= NULL) {
d = fread(buffer, 1, sizeof(buffer), fp1);
fclose(fp1);
#ifdef DEBUG57
random = 0;
#endif
} else {
fort_pseudo_random_data(sizeof(buffer), buffer);
ressu_genbytes(sizeof(buffer), buffer);
d = sizeof(buffer);
#ifdef DEBUG57
random = 1;
#endif
}
#ifdef DEBUG57
for(int c = 0; c < sizeof(buffer); c++) {
if(c % 32 == 0) {
if(c != 0)
fprintf(stdout,"\n");
fprintf(stdout,"restore");
if(random)
fprintf(stdout,"*");
else
fprintf(stdout," ");
fprintf(stdout," %05d ", c);
}
fprintf(stdout," %02x", buffer[c]);
}
fprintf(stdout,"\n");
#endif
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
#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
#ifdef FORT_USE_WEB
static IUTIME fort_next_webmix = 0;
//#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600
#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600
#endif
#define RANDOMNESS_IN_ALPHABETS 2
#define DEBUG65 2
void fort_strrepl(unsigned char *dest,unsigned char *oldstring, unsigned char *newstring)
{
unsigned char *stringstart;
#ifdef DEBUG65
if(verbose) {
fprintf(stdout,"fort_strrepl(): oldstring:%s", oldstring);
fprintf(stdout,", newstring:%s", newstring);
fprintf(stdout,", olddest:%s", dest);
}
#endif
if((stringstart = strstr(dest, oldstring)) != NULL) {
memmove(stringstart + strlen(newstring),
stringstart + strlen(oldstring),
strlen(stringstart + strlen(oldstring)) + 1);
memmove(stringstart, newstring, strlen(newstring));
}
#ifdef DEBUG65
if(verbose) {
fprintf(stdout,", newdest:%s", dest);
fprintf(stdout,"\n");
}
#endif
}
void fort_mix()
{
int webmix, localmix;
unsigned char temp[64];
IUTIME seconds;
seconds = getseconds();
webmix = 0;
localmix = 0;
#ifdef FORT_USE_WEB
if(fort_next_webmix == 0 ||
fort_next_webmix <= seconds) {
fort_next_webmix = seconds + FORT_SECONDS_BETWEEN_WEBMIXES;
fort_next_localmix = seconds + FORT_SECONDS_BETWEEN_LOCALMIXES;
webmix = 1;
localmix = 1;
}
#endif
if(fort_next_localmix == 0 ||
fort_next_localmix <= seconds) {
fort_next_localmix = seconds + FORT_SECONDS_BETWEEN_LOCALMIXES;
localmix = 1;
}
if(!webmix && !localmix)
return;
if(verbose) {
char timebuf[128];
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *)&seconds));
fprintf(stdout,"Fort mix time: %s\n", timebuf);
#ifdef FORT_USE_WEB
if(fort_use_web) {
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *)&fort_next_webmix));
fprintf(stdout,"Next fort webmix: %s\n", timebuf);
}
#endif
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);
#if defined FORT_USE_WEB || \
defined USE_RDRAND || \
defined USE_RDSEED || \
defined USE_NEWRESSU_COMMAND
unsigned char digest[HashLen];
#endif
#ifdef FORT_USE_WEB
if(webmix && fort_use_web) {
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(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, digest);
} else if(!strcmp(scheme,"https")) {
fort_hash_https_page(host, port, p, digest);
}
fort_reseed(sizeof(digest), digest);
}
}
#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);
#endif
#ifdef FORT_USE_RANDOM
memset(temp, 0, sizeof(temp));
fort_readfile_xor(sizeof(temp), temp,
"/dev/random");
fort_reseed(sizeof(temp), temp);
#endif
#if defined USE_RDRAND || \
defined USE_RDSEED
HashCtx hash;
unsigned char digest[HashLen];
#endif
#ifdef USE_RDRAND
memset(temp, 0, sizeof(temp));
if(rdrand_bytes(sizeof(temp), temp)) {
HashInit(&hash);
hash_update_cvar(&hash);
hash_update_ressu(&hash);
HashUpdate(&hash, temp, sizeof(temp));
HashFinal(digest, &hash);
if(verbose) {
fprintf(stdout,", data: ");
for(int c = 0; c < sizeof(temp); c++) {
fprintf(stdout,"%02x", temp[c]);
}
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
newressu_output = 0;
}
fort_reseed(sizeof(digest), digest);
}
#endif // #ifdef USE_RDRAND
#ifdef USE_RDSEED
memset(temp, 0, sizeof(temp));
if(rdseed_bytes(sizeof(temp), temp)) {
HashInit(&hash);
hash_update_cvar(&hash);
hash_update_ressu(&hash);
HashUpdate(&hash, temp, sizeof(temp));
HashFinal(digest, &hash);
if(verbose) {
fprintf(stdout,", data: ");
for(int c = 0; c < sizeof(temp); c++) {
fprintf(stdout,"%02x", temp[c]);
}
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
newressu_output = 0;
}
fort_reseed(sizeof(digest), digest);
}
#endif // #ifdef USE_RDSEED
#ifdef FORT_USE_NEWRESSU_COMMAND
char *commands[] = {
"$newressu -2 -s8 -w8 -l1 --lineno",
"$newressu -2 -s8 -w8 -l1 --lineno --fast",
"$newressu -2 -s8 -w8 -l1 --lineno --urandom",
#ifdef USE_RDRAND
"$newressu -2 -s8 -w8 -l1 --lineno --rdrand",
#endif
#ifdef USE_RDSEED
"$newressu -2 -s8 -w8 -l1 --lineno --rdseed",
#endif
"$newressu -2 -s8 -w8 -l1 --lineno --pseudoressu",
#ifdef RANDOMNESS_IN_ALPHABETS
"$newressu --cn -s8 -w4 -l1 --lineno --single",
"$newressu --deu -s8 -w8 -l1 --lineno --single",
"$newressu --dnk -s8 -w8 -l1 --lineno --single",
"$newressu --eng -s8 -w8 -l1 --lineno --single",
"$newressu --est -s8 -w8 -l1 --lineno --single",
"$newressu --fin -s8 -w8 -l1 --lineno --single",
"$newressu --fra -s8 -w8 -l1 --lineno --single",
"$newressu --gbr -s8 -w8 -l1 --lineno --single",
"$newressu --got -s8 -w8 -l1 --lineno --single",
"$newressu --grc -s8 -w8 -l1 --lineno --single",
"$newressu --ita -s8 -w8 -l1 --lineno --single",
"$newressu --jp -s8 -w4 -l1 --lineno --single",
"$newressu --jp1 -s8 -w4 -l1 --lineno --single",
"$newressu --jp2 -s8 -w4 -l1 --lineno --single",
"$newressu --jp3 -s8 -w4 -l1 --lineno --single",
"$newressu --kor -s8 -w4 -l1 --lineno --single",
"$newressu --ltu -s8 -w8 -l1 --lineno --single",
"$newressu --lva -s8 -w8 -l1 --lineno --single",
"$newressu --nor -s8 -w8 -l1 --lineno --single",
"$newressu --rus -s8 -w8 -l1 --lineno --single",
"$newressu --swe -s8 -w8 -l1 --lineno --single",
#endif
};
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 {
unsigned char command[256];
strcpy(command, commands[c]);
// string:$newressu, newstring:/bin/newressu2, olddest:$newressu -2 -s8 -w8 -l1 --lineno, newdest:/bin/newressu2 -2 -s8 -w8 -l1 --lineno
if(strstr(procname,"newressu") && strlen(procname) < 32)
fort_strrepl(command, "$newressu", procname);
else
fort_strrepl(command, "$newressu", "/bin/newressu");
fort_hash_command(command, digest);
fort_reseed(sizeof(digest), digest);
}
}
#endif // #ifdef FORT_USE_NEWRESSU_COMMAND
}
}
void file_digest(char *filename,unsigned char temp[HashLen])
{
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(temp, &ctx);
}
#define DEBUG88
void fort_init()
{
int c;
unsigned char temp32[32];
memset(temp32, 0, sizeof(temp32));
memset(fort_bytes, 0, sizeof(fort_bytes));
memset(fort_key, 0, sizeof(fort_key));
if(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();
// Initialize buffers
for(c = 0; c < FORT_POOLS; c++) {
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
}
// first key to fort_key
fort_internal_random_data_1(sizeof(fort_key), fort_key);
#ifdef ADDITIONAL_SECRETS
// additional constant randomness from program
fort_reseed(strlen(copyright), copyright);
fort_reseed(strlen(programname), programname);
unsigned char filedigest[HashLen];
file_digest("/proc/self/exe", filedigest);
fort_reseed(strlen(filedigest), filedigest);
fort_reseed(strlen(program_secret), program_secret);
// additional constant randomness
// from you (one more secret adversary
// has to guess)
FILE *fp1;
if((fp1 = fopen(fort_secret_file, "r")) != NULL) {
fclose(fp1);
} else {
if((fp1 = fopen(fort_secret_file, "w")) != NULL) {
fprintf(fp1,"Your secret additional constant data to fort:\n");
fclose(fp1);
unsigned char temp2[160];
sprintf(temp2,"%s -2 -l1 >>%s", procname, fort_secret_file);
system(temp2);
fprintf(stdout,"File %s written\n", fort_secret_file);
}
}
fort_reseed_file(fort_secret_file);
#endif
#ifdef DEBUG10
FILE *fp1;
// Empty events file
if((fp1 = fopen(fort_events_file, "w"))!=NULL)
fclose(fp1);
event_id = 0;
#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(temp32), temp32);
hash_update(&fort_pools[c].pool,
temp32, sizeof(temp32));
FORT_INTERNAL_EVENTS_END(32)
}
#ifdef FORT_INTERNAL_EVENTS
if(fort_internal_events) {
// Create some internal events
for(c=0; c<32; c++) {
FORT_INTERNAL_EVENTS_START(34)
fort_internal_random_data_3(sizeof(temp32), temp32);
FORT_INTERNAL_EVENTS_END(35)
}
}
#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(temp32), temp32);
fort_reseed(sizeof(temp32), temp32);
fort_restore();
// Forget temp
memset(temp32, 0, sizeof(temp32));
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
*/
#ifndef SHA256_H
#include "sha256.h"
#endif
#define aUSE_RDRAND 2
#define aUSE_RDSEED 2
typedef unsigned long long IUTIME;
extern int fort_verbose;
extern int fort_partial_line;
extern int fort_use_web;
extern unsigned char fort_random_file[128];
extern unsigned char fort_secret_file[128];
extern unsigned char fort_pools_file[128];
#ifdef DEBUG10
static char fort_events_file[128] = "fortevents.deb";
#endif
unsigned char cvar[16];
int cvarsize;
void inccvar();
void clearcvar();
void hash_update_cvar(HashCtx *hash);
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);
int rdrand_bytes(int buflen, unsigned char *buf);
int rdseed_bytes(int buflen, unsigned char *buf);
#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(µs); \
}
#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, \
µs);
#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(µs); \
}
#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, \
µs);
#else
#define FORT_EVENTS_END(source)
#endif
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
intelrandom.c
#include <stdio.h>
#include <memory.h>
#include "fort.h"
#include "newressu.h"
#if defined USE_RDRAND || \
defined 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 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 c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"Intel rdrand");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"AMD rdrand");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 100) {
if((ret = _rdrand_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %016lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
newressu_output = 1;
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x", ((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout, "\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDRAND
#ifdef 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 c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"Intel rdseed");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"AMD rdseed");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 1000) {
if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x",((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDSEED
webrandom.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.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 newressu_output;
extern int 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);
}
#define aDEBUG27 2
void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
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);
}
// GET / HTTP/1.0\r\nHost: moijari.com:5006\r\n
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
if((status = write(s, msg, strlen(msg))) < 0) {
fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
perror("write");
fflush(stderr);
}
HashCtx ctx;
unsigned char buffer[1024];
HashInit(&ctx);
bytes = 0;
characters = 0;
while((cnt = read(s, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG27
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&ctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
hash_update_cvar(&ctx);
HashFinal(hash, &ctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
close(s);
}
#define aDEBUG49 2
#define aDEBUG50 2
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
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();
#ifdef DEBUG49
fprintf(stdout,"SSLv23_client_method()\n");
#endif
if((method = (SSL_METHOD *)
SSLv23_client_method()) == NULL) {
fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_new()\n");
#endif
if((ctx = SSL_CTX_new(method)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_new()\n");
#endif
if((ssl = SSL_new(ctx)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"fort_connect()\n");
#endif
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);
#ifdef DEBUG49
fprintf(stdout,"SSL_connect(ssl)\n");
#endif
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:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
#ifdef DEBUG49
fprintf(stdout,"SSL_write(), msg_length:%ld, msg=\"%s\"\n", msg_length,msg);
#endif
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;
unsigned char buffer[2048];
HashInit(&hashctx);
bytes = 0;
characters = 0;
#ifdef DEBUG49
fprintf(stdout, "SSL_read()\n");
#endif
int bytesneeded = 0, bytesheader = 0, bytescontent = 0;
do {
cnt = SSL_read(ssl, buffer, sizeof(buffer));
if(cnt < 0) {
int err, err2;
err = SSL_get_error(ssl, cnt);
err2 = ERR_get_error();
fprintf(stderr, "\n%s: cannot SSL_read()", procname);
fprintf(stderr, ", retval: %d", cnt);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error() %d", err);
fprintf(stderr,", ERR_get_error() %d\n", err2);
perror("SSL_read");
fflush(stderr);
break;
}
#ifdef DEBUG50
write(1, buffer, cnt);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
if(bytesneeded == 0) {
char *p;
p = buffer;
int count = 0;
while(*p != '\0') {
if(!strncmp(p, "\r\nContent-Length: ", 18)) {
bytescontent = atoi(p + 18);
}
if(!strncmp(p, "\r\n\r\n", 4)) {
bytesheader = count;
}
p++;
count++;
}
bytesneeded = bytescontent + bytesheader + 4;
}
} while(SSL_pending(ssl) || bytes < bytesneeded);
if(verbose) {
fprintf(stdout,"\nbytescontent:%d", bytescontent);
fprintf(stdout,", bytesheader:%d", bytesheader);
fprintf(stdout,", bytesneeded:%d", bytesneeded);
fflush(stdout);
}
#ifdef OLD1
#ifdef DEBUG49
fprintf(stdout,"SSL_read()\n");
#endif
while((cnt = SSL_read(ssl, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG49
fprintf(stdout,"SSL_read() round\n");
#endif
#ifdef DEBUG50
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
fflush(stdout);
if(cnt < 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);
}
#endif
fflush(stdout);
hash_update_cvar(&hashctx);
HashFinal(hash, &hashctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
#ifdef NOTUSED
#ifdef DEBUG49
fprintf(stdout,"SSL_shutdown()\n");
#endif
SSL_shutdown(ssl);
#endif
#ifdef DEBUG49
fprintf(stdout,"SSL_free()\n");
#endif
SSL_free(ssl);
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_free()\n");
#endif
SSL_CTX_free(ctx);
close(s);
}
commandrandom.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.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 newressu_output;
extern int 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);
}
#define aDEBUG27 2
void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
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);
}
// GET / HTTP/1.0\r\nHost: moijari.com:5006\r\n
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
if((status = write(s, msg, strlen(msg))) < 0) {
fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
perror("write");
fflush(stderr);
}
HashCtx ctx;
unsigned char buffer[1024];
HashInit(&ctx);
bytes = 0;
characters = 0;
while((cnt = read(s, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG27
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&ctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
hash_update_cvar(&ctx);
HashFinal(hash, &ctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
close(s);
}
#define aDEBUG49 2
#define aDEBUG50 2
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
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();
#ifdef DEBUG49
fprintf(stdout,"SSLv23_client_method()\n");
#endif
if((method = (SSL_METHOD *)
SSLv23_client_method()) == NULL) {
fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_new()\n");
#endif
if((ctx = SSL_CTX_new(method)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_new()\n");
#endif
if((ssl = SSL_new(ctx)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"fort_connect()\n");
#endif
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);
#ifdef DEBUG49
fprintf(stdout,"SSL_connect(ssl)\n");
#endif
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:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
#ifdef DEBUG49
fprintf(stdout,"SSL_write(), msg_length:%ld, msg=\"%s\"\n", msg_length,msg);
#endif
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;
unsigned char buffer[2048];
HashInit(&hashctx);
bytes = 0;
characters = 0;
#ifdef DEBUG49
fprintf(stdout, "SSL_read()\n");
#endif
int bytesneeded = 0, bytesheader = 0, bytescontent = 0;
do {
cnt = SSL_read(ssl, buffer, sizeof(buffer));
if(cnt < 0) {
int err, err2;
err = SSL_get_error(ssl, cnt);
err2 = ERR_get_error();
fprintf(stderr, "\n%s: cannot SSL_read()", procname);
fprintf(stderr, ", retval: %d", cnt);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error() %d", err);
fprintf(stderr,", ERR_get_error() %d\n", err2);
perror("SSL_read");
fflush(stderr);
break;
}
#ifdef DEBUG50
write(1, buffer, cnt);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
if(bytesneeded == 0) {
char *p;
p = buffer;
int count = 0;
while(*p != '\0') {
if(!strncmp(p, "\r\nContent-Length: ", 18)) {
bytescontent = atoi(p + 18);
}
if(!strncmp(p, "\r\n\r\n", 4)) {
bytesheader = count;
}
p++;
count++;
}
bytesneeded = bytescontent + bytesheader + 4;
}
} while(SSL_pending(ssl) || bytes < bytesneeded);
if(verbose) {
fprintf(stdout,"\nbytescontent:%d", bytescontent);
fprintf(stdout,", bytesheader:%d", bytesheader);
fprintf(stdout,", bytesneeded:%d", bytesneeded);
fflush(stdout);
}
#ifdef OLD1
#ifdef DEBUG49
fprintf(stdout,"SSL_read()\n");
#endif
while((cnt = SSL_read(ssl, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG49
fprintf(stdout,"SSL_read() round\n");
#endif
#ifdef DEBUG50
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
fflush(stdout);
if(cnt < 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);
}
#endif
fflush(stdout);
hash_update_cvar(&hashctx);
HashFinal(hash, &hashctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
#ifdef NOTUSED
#ifdef DEBUG49
fprintf(stdout,"SSL_shutdown()\n");
#endif
SSL_shutdown(ssl);
#endif
#ifdef DEBUG49
fprintf(stdout,"SSL_free()\n");
#endif
SSL_free(ssl);
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_free()\n");
#endif
SSL_CTX_free(ctx);
close(s);
}