#include #include #include #include #include #include #include #include #include #include /* Not required, optimizes x86-64 ASM */ /*#include */ /* * If you make an experimental changes to the code, you want to rename * the program, then change you must the program name everywhere it * appears, both in comments, and in code. Search and replace everything * up * to the period in the filename. Then there is one hardcoded filename * length that needs to be exactly the length of the new filename. * * if (strncmp(line, "testecbs64.c", 12) != 0) { * * That line is the only place you need to change anything other than * search and replace filename. That's in the "read config file" section * of code that goes through the argv CLI arguments. That's assuming you * aren't changing the bitsize of the componenets. If you convert from * 64 bit version to 32 bit version or 16 to 64, or whatever, you have * to adjust the sprintf's and printfs in the logstate and dump functions. * Also, the read state from dump file CLI processing has to be adjusted, * and all the variables pertaining to state and setting state have to * be adjusted. But for just using the same bit size, and adding printfs * or hardcoding values or changing #defines and whatnot, all you have * to change is the name where it appears as described above. * * * To rebuild the helptext do this. Use your new filename if its renamed. * You could just do testecbs64 -h > helptext.txt but there are quoted * strings that will cause syntax errors if not escaped when moving * back to C code. Therefor you need to extract the HELPLINEs text, then * edit, preverving and using backslashed quotes when wanted for output * of the -h option. And then surround each line with quotes, and end * each line with a comma to make it C source code. Then use wc -l to * find the helpline count to update in the source code. I always have * at least two spaces before each line of helptext, even blank lines * in the help output are really two spaces followed by a newline. That * makes iut easy to grep and modify, and easy to read on the screen for * the user. * grep '^" ' testecbs64.c > testecbs64.helptext * Next, I remove all the open double quotes, and the close quote and * comma at EOL. Then edit the document and make it look pretty, * * If you have snip, you can strip off the C syntax in one step, like this * grep '^" ' testecbs64.c | snip "\"" | snip "\",$" > helptext.txt * Otherwise, just use search and delete in vi or do whatever. Then, * edit and make it match reality or whatever you want. * When finished, add the C syntax back like this. * cat helptext.txt | snip "^" "\" " | snip "$" "\"," > helptext.c * Or, just use vi and insert '" ' (doublequote space space), and at * the end of line add '",' (doublequote comma). * Find the number of lines with wc -l helptext.c * Then include it in this file by deleting HELPCOUNT lins below the * helplines declaration and read in the new file. * DONT FORGET TO UPDATE HELPLINECOUNT with the new value. * DONT FORGET TO ESCAPE QUOTEs as needed. */ #define HELPLINECOUNT 337 char *helplines[HELPLINECOUNT] = { " ", " testecbs64 is a Pseudo Random Number Generator, (PRNG).", " By default, testecbs64 will simply print out pseudo random numbers", " to stdout forever. It is meant for testing the algorithm and showing", " that the algorithm can pass statistical tests even with some features", " disabled.", " ", " Usage: testecbs64 -ffilename -d -dd -n[0-9.+BKMGTP] -r[0-9]+ -s[0-9]+ -c[1-4] -l -t -z|Z -E -D -C1n -C2n \"string\" filename ", " ", " Command line arguments are optional. There are program control", " arguments, and there are PRNG seed arguments. Anything that starts", " with \"-\" is a control option. Control options are never used for", " seed data. Anything that does NOT start with \"-\" is used as seed", " data.", " ", " The program control options have two varieties that may or may not", " require some numeric argument. The output CLI options are about", " controling output, how many numbers to output, logfile or not,", " dump the state and so on. The configuration options turn off parts", " of the algorithm or set specific values for parts of the state.", " ", " -d ", " -dd dump the state to STDOUT. They first intialize with", " any other CLI options or default, then print the state and exit.", " The single -d omits the LFSR element values. The double -dd", " includes the LFSR elements, and that can be saved to a file", " and used for the -f option to set the state from a file. ", " ", " -l saves the starting state like -dd, to a logfile named", " testecbs64.log, and continues on, outputting pseudo random", " numbers. -l creates a new file named testecbs64.log if it does", " not exist, otherwise it appends to the existing file.", " ", " -E encrypts data read from STDIN and writes to STDOUT.", " No Fiestel structure, just a couple of XORs and intermmediate", " feedback into the LFSR state. ", " ", " -D Decrypts data read from STDIN and writes to STDOUT.", " ", " -ss causes single step output of the state variables for every", " pseudo random number generated. -ss also turns off stdout of the", " binary pseudorandom numbers, only the single step output is seen.", " ", " These CLI options require a numeric argument consisting of ascii", " digits specify the value of the parameter you are setting.", " ", " -n specifies how many numbers to output. The digit string can be", " ended with an upper case units specifier, B = bytes, K = kilobytes,", " and so on. These are base 2 units K = 1024, NOT 1000.", " ", " -s sets the LFSR length (size) and turns off resizing. -S allows", " for later resizing but will start with the initially specified", " size.", " ", " -r sets the ressize interval in powers of 2 where the setsize", " function will be called pseudorandomly, approximately once in", " every 2^resetpower output numbers. -R allows the resize function", " to be used even if the -s option is used to set the initial size.", " ", " -e sets the entropyflag which cuases the resize function to add", " entropy in the form of a call to gettime() using CLOCK_MONOTONIC.", " Adding entropy will generate pseudo random numbers that cannot be", " predicted forwards or backwards even given the complete state.", " ", " -f filename, requires a file name which may immediately follow", " or follow whitespace as the next CLI argument, and reads state", " configuration from that file if it's a valid dump file.", " ", " All the above options are used to configure the normal algorithm.", " The ones below, disable some algorithm functions so it can be", " tested with various incomplete implementations in a single program.", " ", " -c specifies the number of counters to REMOVE from the algorithm.", " -c also requires a digit from 1 to 4. 4 disables all counters, 3", " leaves one counter, and it starts from the last counter, so the", " least used counters are removed first.", " ", " -t disables tap swapping. This is just a binary toggle.", " ", " -z sets all state values to 0. This also disables resizing and", " sets the LFSR length to MINVAL+1 which is currently 9. -s can", " be used to set the size to any other value. The upper case", " switches can override the -z option and allow resizing.", " ", " -Z sets all LFSR element values to 0 but randomizes tap positions.", " ", " ", " -C1n", " -C2n sets constant1 and constant2 and uses ecbs64const function", " instead of ecbs64. The ecbs64const function is identical to", " ecbs64 except the two formula lines are replaces with constant", " value updates.", " ", " All other CLI provided input is checked for being a readable", " file and if so, opened and read for seed input. If the CLI", " argument is not a valid control option and not a readable file,", " then the ascii values are used as seed data.", " ", " ", " Below is more detailed explanation", " of each CLI option and arguments", " ", " -d = dump the config state (except LFSR elements), to STDOUT", " and exit. Regardless of any other options, dump config", " except the LFSR element values. Use this to see maximum", " and minimum compiled LFSR sizes.", " ", " -dd = Dump the config state plus LFSR state to STDOUT and exit.", " Like -d, this will dump and exit regardless of any other ", " CLI otptions. lower case -dd also prints out every element", " of the LFSR in addition to adders and taps. Redirect this", " output to a file and you can use that file with -f switch", " to set the state to exactly those same values. You can edit", " the file to set whatever numbers you want, just keep the", " same format and make sure the values are in the proper", " range. No negative numbers for example.", " ", " -l = Log initial state in a logfile. This option will log the", " full state of the LFSR, exactly like -dd, but to a logfile", " named testecbs64.log. Sections of the logfile can be used", " as configuration file, but they must be split out into", " separate, standalone files.", " ", " -E = Encrypt data from STDIN. All the algorithm controls will", " still work, and its just toy encryption. But it can be", " used for testing. -E and -D require a file piped through", " the program to encrypt the data from. The user seed is", " not hashed in any way and some of it may be skipped or", " ignored. See the tesetecbs64.readme file for details.", " Encrypt and Decrypt ignore single step and outputlimit.", " ", " -D = Decrypt data from STDIN. All the algorithm controls will", " still work, and its just toy encryption. But it can be", " used for testing.", " ", " -ss = single step output of the state variables for every pseudo", " random number generated. -ss also turns off stdout of the", " binary pseudorandom numbers, so only the single step output", " is seen. Each number generated produces three lines of", " output similar to these for LFSR of size 16 elements.", " ", " 154 36 184 14 RETVAL 246 A", " 153 141 206 107 129 113 110 45 227 133 250 115 118 77 58 12 S", " 6 2 4 7 3 5 8 1 T", " ", " The position of the taps in the T line indicates the LFSR", " element they currently point to. Single step cannot be used ", " with -E or -D", " ", " -f = Read state config from previously dumped data file. The", " file must be exactly the same format as a file created", " using the -dd option. It will include all LFSR values. If a", " file is specified for state initialization, then the setsize", " option \"-s\" can still be used, but will also reset all the", " state data. Edit the file rather tha using CLI option.", " ", " -z = Zero out all LFSR state and set taps to 0-7. This initially", " sets lfsralen to MINLEN+1 but it may be reset by the resize", " function. The -z switch does not affect other program", " control options, it just removes the seed step and starts", " the lfsr with all zero's in the state, except the tap values", " which have to be unique. The tap values are set to elements", " 0 - 7 of the LFSR. Since seeding is skipped, the lfsr", " length is never set, so it defaults to MINLEN-1 unless", " overridden by the -S option. The resize function turns off", " resizing unless the special CLI option -S (upper case) is", " used for the size, OR -R (upper case), is used to set the", " resetpower value. ", " ", " -Z = Zero out LFSR state and counters, but randomizes the taps.", " Otherwise its the same as -z. The uppercase -Z option calls", " the setsize function, but zero's out everything except", " the tap positions.", " ", " -s = Set the lfsrlength. This sets the LFSR length if possible.", " The -s option also turns of resizing completely because", " it makes no sense to set a length and have it randomly", " changed. If no seed bytes are provided, then the size can", " be any value between MINLEN and MAXLEN. But if seed bytes", " are provided, then the ecbs64seed function sets the LFSR", " length to number of seed bytes recieved. The -s switch can", " set the length greater than number of seed bytes recieved,", " if some are also provided. If setsize is used with -f to", " read from a dump file, then resetpower will be set to zero", " if not zero and the resize function will be called. This", " will change the LFSR taps and LFSR element values.", " ", " -S = Allow resizing after starting from specified LFSR length.", " Normally the lower case -s option turns off reszing. The", " upper case option allows for a specified initial LFSR length,", " and resizing thereafter. The -z option also normally turns", " off resizing and sets minimal length. Either -S or -R can", " be used to allow the resize function when it would normally", " be ignored with the lower case switches.", " ", " -r = Set the reset interval. The -r option requires a number", " from 9 to 63 be provided. The number can be a separate", " CLI argument or immediately follow the -r. By default the", " LFSR resets it's size and taps pseudorandomly every 16", " million calls or so. The reset interval is a power of 2,", " from 9 to 63 which is used to set the reset frequency.", " We set the reset value to (2^reset) -1 and if a certain", " state value & reset == 0, then we call the resize function.", " This means, we are calling based on the number of 1 bits", " in a row on the small end of the state value. The reset", " interval is stored as variable resetpower. If resetpower = 0,", " then resetting and resizing the LFSR is completely turned", " off. Otherwise, the value is used to set the AND value to", " that many one bits in a row from small end. Values less than", " 17 can cause extra inefficient CPU usage, because ecbs64()", " might try to call ecbs64) while ecbs64setsize() is", " calling ecbs64(). These calls are ignored. The default", " value is 24. Any value < 9 is treated same as zero and", " turns off resizing altogether.", " ", " -R = Set the resetpower when using -s or -z. The -z option", " normally turns off resizing, even with the -s switch.", " The -s switch normally turns off resizing. Upper case", " R can be used to force the resize function. Either -S", " or -R can be used to force the resize function when it", " would normally be ignored with the lower case switches.", " ", " -e = Add entropy in the ecbs64setsize function. This causes setsize", " to add current seconds and nanoseconds from", " gettime(CLOCK_MONOTONIC, &curtime) system call. The values", " returned are mixed and stored in variables seconds and ns,", " and also the previous values are stored in lastseconds and", " lastns. Those last values are used to update the LFSR elements", " determined by the value of the shift variable. The use of the ", " last values introduces a delay, and adding to LFSR elements", " will also introduce an amount of delay. This output cannot", " be reproduced. The best you can do is start from the same", " initial seed. The delay is intentional but you can simply", " call ecbs64setsize() a second time before obtaining any numbers.", " ", " -t = Turn off tap swapping. This causes the taps to be fixed in", " position, like most other LFSRs where the LFSR is defined", " by the tap values. By default, (without the -t switch), one", " tap is randomly selected to be swpped with its neighbor to", " the right on each call to ecbs64.", " ", " -c = Cripple the adders by removing the last n adders. The", " number n may follow the -c without a space or may be given", " as the following CLI argument. The value ranges from 1 to 4", " inclusive. 0 does not make sense, that would do nothing.", " Adders are removed in order, adder4, adder3, adder2 and adder1.", " They are simply not used anymore.", " 1 is the leaset extreme, 4 removes ALL adders.", " 1 = dont use adder4", " 2 = dont use adder4 adder3", " 3 = dont use adder4 adder3 adder2", " 4 = dont use adder4 adder3 adder2 adder1", " ", " -n = Output exactly n 8 bit numbers. Output bytes will be same", " as n. The -n option requires a number and optionally, a", " Units tag consisting of one of the following letters:", " B = Bytes", " K = Kilobytes", " M = Megabytes", " G = Gigabytes", " T = Terabytes", " P = Petabytes", " The optional Units specifier, must be appended to the last", " digit of the number given. It cannot be a seprate CLI", " argument. This will output exactly that many numbers unless", " overriden by a dump switch, (-d or -dd. Source of seed data", " makes no difference, if numbers will be output, then it will", " be this many, if specified. The outputlimit is ignored when", " using -D and -E.", " ", " -C1n", " -C2n sets constant1 and constant2 repectively where n may", " follow immediately or separated by a space. Defaults", " are constant1 = 170, constant2 = 85. They are always", " used together so if only one is set the other will use", " its default value. When either of these are set from CLI,", " a flag is set that uses a modified ecbs64 PRNG algorithm", " which is identical to the real ecbs64, EXCEPT, instead of", " using the two formula lines, ecbs64const function returns", " a constant value where the formulas would have been. This", " simulates a formula with period length of 1. The real ecbs64", " function does not use constant1 and constant2, they are", " replacements for the formula lines in ecbs64const() only.", " ", " None of the program control options are used as seed data or", " counted as seed bytes used, regardless whether they are used or", " rejected as out of bounds.", " ", " Any other CLI arguments not used to control the program are used", " as seed data, applied byte by byte as recieved into the LFSR state.", " ", " The numbers for -n , -s, -c, -r, -C1, -C2 and the filename", " for -f may follow immediately after the name or number, or", " separated by a space.", " ", " Later CLI arguments may override earlier CLI arugments, as you", " would expect. The -D and -E options cause any -ss or -n to be", " ignored regardless of position in argument list", " ", " If a seed option is a readable file greater then 0 bytes in", " size, then the file is opened and all bytes are read in and", " added to the LFSR state. If the option is a file but its not", " readable or it doesn't exist, then the filename is used as seed", " data and counted as bytes read in. If the file is opened and read,", " then the filename itself is not used as seed data. All CLI seed", " options are tested for being a file that can be opend and read.", " ", " Seed data is added to the counters first, and then the LFSR", " elements in order until finally wrapping back to the counters", " and then LFSR elements again if enough seed data is provided.", " If no seed data is provided and no dump file, then /dev/urandom", " is used to fill in the state. This defaults to MAXLEN-1 initial", " size. If user seed input is provided, then the lfsrlen is first", " set to MAXLEN-1 and setsize is called fill all lfsr elements.", " After this, the adders are updated by ecbs64 and then ecbs64setsize", " is called a second time with user specifiied or determined by", " totalseedchars lfsrlen. This becomes the initial lfsralen.", " By this method, the adders are always randomized with lfsr", " elements and taps.", " ", " The ecbs64setsize function does not alter the adders, only", " the taps and lfara elements. Thats why we update them", " initially here. That could all be in a seed function, but", " you can seed and initialize any way you want. Nobody will", " ever want to use my CLI processing but it doesn't matter", " much, the ecbs64setsize function is really all you need, and", " a few seed bytes in lfsra.", " ", " This is the 8 bit version. The maximum LFSR length can only be", " 127 bytes long. I use MINLEN 8 and MAXLEN 127 for simulating", " the algorithm on something like a 6502 chip. ", " ", " See the readme file, testecbs64.readme for more algorithm", " discussion.", " ", " Last Update: Fri Apr 15 02:10:35 PDT 2022", " ", }; /*#### END char *helplines[HELPLINECOUNT] = { ####*/ /* This is here so you can just grep ^comp and cut and paste to recompile I found out the -lrt is needed for clock_gettime on older Linux. compile gcc -o testecbs64 -Wall -O3 -lrt testecbs64.c */ struct timeval tv; /* Used to print the time for -d and -D output */ /* All these must be powers of 2. MAXLEN must be >= MINLEN * 2. You could use different hardcoded values really, but for ease of debugging I can check these and know that things are fairly normal after all the typo's and off by one errors. These restrictions are just a convenience, all you really need for the algorithm is the data structures and fairly random data. For integrity of the output, I restrict the minimum lfsr length to MINLEN+1 to ensure it is always at least one greater than a power of 2. This will introduce a slight bias towards lfsralen = MINLEN+1 twice as often as any other length. I take steps to counter that bias below. Any length from MINLEN+1 to MAXLEN-1 is valid. MINLEN and MAXLEN are not allowed as lfsralen values. Thats to avoid needing one extra byte for the single largest possible length if MAXLEN were 256 or 65536. The larger the state the longer the period and the longer it takes to diffuse. The shortest state is the fastest diffusion but the period will not be long enough. In the 8 bit version we could use length = 9. But that will be too easy for the cryptographer. So I allow much longer lengths to make the state just that much harder to crack. MAXINP and MAXOUT technically don't have to be powers of 2, but for ease of programming and efficiency, I force the requirement arbitrarily. If you want to change that, you would have to review the code for all power of 2 dependencies, and there are quite a few. My preferred values are #define MAXINP 65536 #define MAXOUT 65536 #define MAXLEN 128 #define MINLEN 32 */ /* This is the 64 bit version */ /* MAXLEN can't be more than 128 because we use signed char */ /* values based on these. It's already considered too big anyway. */ #define MAXINP 65536 #define MAXOUT 65536 #define MAXLEN 32 #define MINLEN 8 /* functions */ void ecbs64entropy (void); void ecbs64setsize(unsigned char thenewsize); unsigned long long int ecbs64 (void); unsigned long long int ecbs64const (void); void singlestep(unsigned long long int output); void singlestepinit(void); /* * STATE STORAGE variables. These need file scope * so all functions can see them. These are all used by ecbs64(), so * we want them to be as small as possible to fit into cache. */ unsigned long long int adder1 = 0; /* These are the counters. */ unsigned long long int adder2 = 0; unsigned long long int adder3 = 0; unsigned long long int adder4 = 0; unsigned int resetpower = 24; /* Must be 9 - 64 */ unsigned long long int power = 16777215; /* remainder bits in last byte */ unsigned char lfsralen = MINLEN+1; /* length to be strictly controlled */ unsigned char shift = 63; /* Must be initialized correctly */ unsigned char maxtap = MINLEN; /* always set to lfsralen - 1 */ unsigned long long int lfsra[MAXLEN]; /* This is the main state storage */ unsigned char tapa1 = 0; /* Each tap has to be unique. */ unsigned char tapa2 = 1; /* No two taps can have the same value */ unsigned char tapa4 = 2; /* we have to start with known values */ unsigned char tapa3 = 3; /* We use unsigned 8bit integers */ unsigned char tapa5 = 4; /* We could use signed ints too */ unsigned char tapa6 = 5; /* I used unsigned and maxtap for */ unsigned char tapa7 = 6; /* easy to understand code. */ unsigned char tapa8 = 7; /* */ unsigned char taps[MAXLEN]; /* Shuffle tap values in ecbs64setsize */ struct timespec curtime; /* Get entropy from getttime() */ unsigned long long int ns = 0; /* nanoseconds for adding entropy */ unsigned long long int seconds = 0;/* seconds - poor mans entropy */ unsigned long long int lastns = 0; /* use last results for current update */ unsigned long long int lastseconds = 0; /* gives us a delay in adding entrypy*/ int entropyflag = 0;; /* flag to add entropy */ /* Below are for testing seeding, not really part of the algorithm. */ unsigned char sindex = 0; /* index when filling lfsra from CLI */ unsigned char sindexshift = 0; /* index when filling lfsra from CLI */ unsigned char resetflag = 0; /* For use with zeroflag only */ /* * The constant1 and constant2 values are NOT part of ecbs algorithm. * They are there to replace the formula lines with constant values. * The fundamental mixer of the algorithm always returns a constant value. * Compare the output with the formulas. */ unsigned long long int constant1 = 12297829382473034410LLU; /* For ecbs64const() function which */ unsigned long long int constant2 = 6148914691236517205LLU; /* replaces each formula with a constant*/ unsigned char constantflag = 0; /* Flag to use ecbs64const */ /* * All these are just for testing ecbs64. They have nothing to do with * the algorithm. These are global for convenience, so you can put a * logstate() anywhere, and things like that. ecbs64 function is modified * to use these where it needs to be. All the 0 or 1 flags are as you * expect, 0 means off, and 1 means on. I try to avoid things like * if (!done) but sometimes its the easiest and clearest way with * restpect to the surrounding code. */ unsigned long long int adders[4]; /* For sscanf to read < 8 bit numbers */ int32_t dumpstate (void); /* Dumps full or partial state to STDOUT */ int32_t dumpstateerr (void); /* Dumps full or partial state to STDERR */ int32_t logstate(void); /* Dumps full state to file testecbs64.log */ unsigned int totalseedchars; /* How much seed data we got in bytes */ unsigned int dump = 0; /* Dump level, 0 is minimal. */ unsigned int logging = 0; /* Default is to never log state */ unsigned int cripple = 0; /* Removes n adders from service */ unsigned int tapswap = 1; /* binary flag to override tap swaps */ unsigned int setsize = 0; /* binary flag and value > 0 is length */ unsigned char zeroflag = 0; /* Tells us to zero out adders and lfsra */ unsigned char encrypt = 0; /* Encrypt data flag, needs to read stdin */ unsigned char decrypt = 0; /* Decrypt data flag, requires stdin */ unsigned char lastchar = 0; /* Needed by encrypt and decrypt */ int tapsint[MAXLEN]; /* Used to read values from dump file */ /* Everything above has to be global file scope for the logstate and dump */ /* functions. */ /***************************************************************************/ int32_t main(int32_t argc, char ** argv) { int32_t i = 0; /* primary loop counter */ int32_t j = 0; /* secondary loop counter */ int32_t readcount = 0; /* bytes read from last input file or CLI string */ unsigned int tmp = 0; /* used to calculate CLI params */ unsigned int tshift = 0; /* used to calculate CLI params */ int32_t done = 0; /* used to indicate final success or failure */ int32_t binaryfileflag = 0; /* Indicates non-ascii data in config file */ char curargv[MAXINP]; /* for reading in CLI arguments */ int32_t curargc = 1; /* The current CLI argument we are working on */ FILE *INP; /* For reading files */ unsigned char seedbuffer[MAXINP]; /* buffer for urandom seed data */ unsigned long long int outbuffer[MAXOUT]; /* for binay output data */ uint32_t maxbytesok = 0; /* for self test that #defines are valid */ uint32_t maxoutok = 0; /* for self test that #defines are valid */ uint32_t maxlenok = 0; /* for self test that #defines are valid */ uint32_t minlenok = 0; /* for self test that #defines are valid */ char filename[256]; /* for reading in config files, not data */ uint32_t readflag = 0; /* binary flag for read in config file */ char line[1024]; /* used to read in the config file line by line */ char junk1[64]; /* used to ignore junk strings with scanf() */ char junk2[64]; /* used to ignore junk strings with scanf() */ unsigned long long int outputlimit = 0; /* number of numbers to output */ char limitunits = 'B'; /* units to count outputlimit in. B K M G T P */ int singlestepflag = 0; /* Set to 1 calls singelstep state output func. */ /* Quick check to make sure the defined sizes are powers of 2 */ j = 1; for (i=3; i<24; i++) { if (MAXINP == (j<= MINLEN*2 %u\n", MAXLEN, (MINLEN*2)); exit(1); } for (i=0; i 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Cripple requested but level not given, Last CLI.\n"); printf(" Cripple level must be > 0 and < 4\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ( (line[0] < 48) || (line[0] > 57) ) { printf("Error: Cripple requested but level not given.\n"); printf(" Cripple level must be > 0 and < 4\n"); return(0); } } cripple = 0; i = 0; if ((line[0] >= 48) && (line[0] <= 57)) { cripple = line[i]-48; ++i; } if (cripple > 4) { cripple = 4; } if (cripple < 1) { cripple = 0; } ++curargc; continue; } if (strncmp(curargv, "-t", 2) == 0) { tapswap = 0; ++curargc; continue; } if ((strncmp(curargv, "-d", 2) == 0) && (strlen(curargv) == 2)) { dump = 1; ++curargc; continue; } if ((strncmp(curargv, "-dd", 3) == 0) && (strlen(curargv) == 3)) { dump = 2; ++curargc; continue; } if (strncmp(curargv, "-z", 2) == 0) { zeroflag = 1; ++curargc; continue; } if (strncmp(curargv, "-n", 2) == 0) { readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Specified number requested but amount not given.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) && (line[0] > 57)) { printf("Error: Specified number requested but amount not given.\n"); return(0); } } i = 0; outputlimit = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { outputlimit = (outputlimit*10) + (line[i]-48); ++i; } if (line[i] == 0) { limitunits = 'B'; } else { limitunits = line[i]; } switch (limitunits) { case 'K': outputlimit *= 1024LLU; break; case 'M': outputlimit *= 1048576LLU; break; case 'G': outputlimit *= 1073741824LLU; break; case 'T': outputlimit *= 1099511627776LLU; break; case 'P': outputlimit *= 1125899906842624LLU; break; default: break; } limitunits = 'S'; /* this is now used as a flag that says Set. */ ++curargc; continue; } /* Check for reset interval option. */ if ( (strncmp(curargv, "-r", 2) == 0 ) || (strncmp(curargv, "-R", 2) == 0) ) { if ( strncmp(curargv, "-R", 2) == 0 ) { resetflag = 1; } readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Resize power of 2 interval not given. Last CLI\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Resize power of 2 interval not given.\n"); return(0); } } i = 0; resetpower = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { resetpower = (resetpower*10) + (line[i]-48); ++i; } if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { power = (1 << (resetpower-1)) -1; } else { power = 0; resetflag = 0; } ++curargc; continue; } /* Here is where we check for a config file to read in. */ if (strncmp(curargv, "-f", 2) == 0) { readcount = strlen(curargv); if (readcount > 2) { memccpy(filename, &curargv[2], 0, 80); } else { /* If the filename was provided with a space after the "-f" then we have to */ /* get the next CLI argument and check that its a valid filename. If we are */ /* already on the last CLI argument then the filename is missing. */ ++curargc; if (curargc > argc) { printf("Error: Config file name not specified for -f CLI option.\n"); return(0); } memccpy(filename, argv[curargc-1], 0, 80); } /* Now we have the filename, or there was an error and we aborted above. */ errno = 0; INP = fopen(filename, "r"); if (errno == 0) { done = 0; /* * We won't be done until the last LFSR value is read in. But if it doesn't * exist for some reason, then we have to use some other way of setting the * done flag. If the input file ends, thats a good check. I could also * add a line counter because if we get millions of lines, thats obviously * wrong. * * If the very first line does NOT start with testecbs64.c then we * know this is not a config file. But we will try to find a clue for * the user before we exit. */ fgets(line, 80, INP); if (strncmp(line, "testecbs64.c", 12) != 0) { i = 0; binaryfileflag = 0; while ((line[i] != ' ') && (line[i] != '\n') && (line[i] != 0) && (i < 40)) { if (line[i] > 126) { binaryfileflag = 1; } ++i; }; line[i] = 0; /* If we get any non-ascii character we know this is not a valid config file */ if (binaryfileflag) { printf(" Error: File \"%s\" is not a config file for testecbs64\nI found gibberish instead of \"testecbs64.c\"\n", filename); } else { /* If it was a text file, show them what we got so they know what went wrong */ printf("Error: File \"%s\" is not a config file for testecbs64\nI found \"%s\" instead of \"testecbs64.c\"\n",filename, line); } return(0); } while ((!done) && (fgets(line, 256, INP))) { if ( (strncmp(line, "#", 1) == 0) || (strncmp(line, " ", 1) == 0) ) { continue; } if (strncmp(line, "constantflag = ", 15) == 0) { sscanf(line, "%s %s %c %s %s %llu %s %s %llu", junk1, junk2, &constantflag, junk2, junk1, &constant1, junk1, junk2, &constant2); constantflag -= 48; continue; } if (strncmp(line, "totalseedchars = ", 17) == 0) { sscanf(line, "%s %s %u %s %s %u %s %s %u", junk1, junk2, &totalseedchars, junk2, junk1, &cripple, junk1, junk2, &tapswap); /*fprintf(stderr, "GETOPTS totalseedchars = %u\n", totalseedchars);*/ continue; } if (strncmp(line, "adders = ", 9) == 0) { sscanf(line, "%s %s %llu %llu %llu %llu %s %s %d", junk1, junk2, &adders[0], &adders[1], &adders[2], &adders[3], junk1, junk2, &resetpower); adder1 = (unsigned long long int) adders[0]; adder2 = (unsigned long long int) adders[1]; adder3 = (unsigned long long int) adders[2]; adder4 = (unsigned long long int) adders[3]; /* The adder values don't much matter, as long as they fit in 8 bytes. * But the lfsrlen must be accurate and it must fit within our builtin * #defines for MINLEN and MAXLEN. The tap values should also be checked. * The only thing we can really check is that we are getting 8 bit values. * Since we are reading and storing them into 8 bit chars, they can't be * out of range, but if they are out of range in the file they will be * truncated modulo 2 to 8 bit values so they will fit without error. * Thats why you might want to use -D with the -f flag, to confirm that * it reads the exact same thing it output before. */ /*fprintf(stderr, "GETOPTS reset %d resetpower %d lfsralen %d setsize %d\n", reset, resetpower, lfsralen, setsize);*/ if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { /* reset is the total number of unsigned chars used to store 2^resetpower */ power = (1 << (resetpower)) -1; } /*fprintf(stderr, "GETOPTS reset %d resetpower %d lfsralen %d setsize %d\n", reset, resetpower, lfsralen, setsize);*/ continue; } if (strncmp(line, "lfsralen = ", 11) == 0) { done = 1; sscanf(line, "%s %s %d %s %s %d", junk1, junk2, &tmp, junk1, junk2, &tshift); lfsralen = (unsigned char) tmp; maxtap = lfsralen -1; shift = (unsigned char) tshift; /* printf("DEBUG lfsralen = %d shift = %d\n", lfsralen, shift); */ if ((lfsralen <= MINLEN) || (lfsralen >= MAXLEN)) { printf("Error: Config file \"%s\" LFSR length %d is out of range.\n", filename, lfsralen); printf(" LFSR length must be > %u and < %u\n", MINLEN, MAXLEN); return(0); } for (i=0; i<8; i++) { if (fgets(line, 80, INP) != NULL) { sscanf(line, "%s %s %u", junk1, junk2, &tapsint[i]); } else { printf("Error: Config file \"%s\" Only got %d taps\n", filename, i); printf(" 8 taps are required for ecbs64\n"); return(0); } } for (i=0; i<(8); i++) { taps[i] = (short int) tapsint[i]; } /* ##ec */ for (i=0; i<(8-1); i++) { for (j=i+1; j<8; j++) { if (taps[i] >= lfsralen) { printf("Error: Config file \"%s\" tap %d =%d is > lfsralen %d\n", filename, (i+1), taps[i], lfsralen); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } if (taps[i] == taps[j]) { printf("Error: Config file \"%s\" tap %d == tap %d = %d\n", filename, (i+1), (j+1), taps[i] ); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } } } if (taps[7] >= lfsralen) { printf("Error: Config file \"%s\" tap 8 = %d is > lfsralen %d\n", filename, taps[7], lfsralen); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } tapa1 = (unsigned char) taps[0]; tapa2 = (unsigned char) taps[1]; tapa3 = (unsigned char) taps[2]; tapa4 = (unsigned char) taps[3]; tapa5 = (unsigned char) taps[4]; tapa6 = (unsigned char) taps[5]; tapa7 = (unsigned char) taps[6]; tapa8 = (unsigned char) taps[7]; for (i=0; i 3) { memccpy(line, &curargv[3], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Constant1 requested but value not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Constant1 requested but size not given.\n"); return(0); } } i = 0; constant1 = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { constant1 = (constant1*10) + (line[i]-48); ++i; } ++curargc; continue; } if (strncmp(curargv, "-C2", 3) == 0) { constantflag = 1; readcount = strlen(curargv); if (readcount > 3) { memccpy(line, &curargv[3], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Constant2 requested but value not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Constant2 requested but size not given.\n"); return(0); } } i = 0; constant2 = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { constant2 = (constant2*10) + (line[i]-48); ++i; } ++curargc; continue; } /* * Here we check for a string of digits to indicate a LFSR length. * But if its already set, or if readflag is set, then we already got * the length from the config file or previous -s. */ if ( ((strncmp(curargv, "-s", 2) == 0) || (strncmp(curargv, "-S", 2) == 0)) && (setsize == 0) ) { /* * First check ifd resetflag is already set, or if not, is it S or * little s? Little s does NOT set resetflag, and turns off reset. * But big S allows resetpower, and thus reset to be non zero. This * means we need a resetflag to indicate this later on so we know that * setsize calls are allowed. This is to be able to change the default * where setsize turns off resizing. */ if ((strncmp(curargv, "-s", 2) == 0) && (!resetflag)) { resetpower = 0; } else { if (strncmp(curargv, "-S", 2) == 0) { resetflag = 1; } } readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Specified LFSR size requested but size not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Specified LFSR size requested but size not given.\n"); return(0); } } i = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { setsize = (setsize*10) + (line[i]-48); ++i; } /* It has to be within our defined range. */ if (setsize <= MINLEN) { setsize = MINLEN+1; } if (setsize >= MAXLEN) { setsize = MAXLEN-1; } ++curargc; continue; } /* * If the readflag is not set then anything that gets down here is not a * program control option so its either CLI seed data or a file to * read in for seed data. */ if (!readflag) { errno = 0; INP = fopen(curargv, "r"); if (errno == 0) { /* If the file is readable, read in a chunk and add it to the LFSR. */ readcount = fread(seedbuffer, 1, (MAXINP), INP); if (readcount > 0) { while (readcount > 0) { fprintf(stderr, "readcount = %d sindex = %d\n", readcount, sindex); totalseedchars += readcount; for (i=0; i= 64) { sindexshift = 0; } ecbs64setsize(MAXLEN-1); adder1 += ecbs64(); adder2 += ecbs64(); adder3 += ecbs64(); adder4 += ecbs64(); } } readcount = fread(seedbuffer, 1, (MAXINP), INP); } fclose(INP); } else { /* If its an empty file, then use the filename string as seed data */ fclose(INP); readcount = strlen(curargv); totalseedchars += readcount; for (i=0; i 0) && (!readflag)) { printf("Error: Only got %d seed bytes. I need at least %d bytes.\n", totalseedchars, MINLEN); return(0); } /* fprintf(stderr, "DEBUG01 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); */ /* * Now in this section, if we dont get any seed data and no config file, * then its all strictly the system PRNG to seed the LFSR. */ if ((totalseedchars == 0) && (!readflag)) { readcount = 0; errno = 0; INP = fopen("/dev/urandom", "r"); if (errno == 0) { readcount = fread(lfsra, sizeof(unsigned long long int), 5, INP); if (readcount != 5) { printf("You should never see this but I couldn't read 5 bytes from dev/urandom.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } else { adder1 = lfsra[0]; adder2 = lfsra[1]; adder3 = lfsra[2]; adder4 = lfsra[3]; lfsralen = lfsra[4]; lfsralen |= (MINLEN+1); lfsralen &= (MAXLEN-1); } readcount = fread(lfsra, sizeof(unsigned long long int), MAXLEN-1, INP); fclose(INP); if (readcount != (MAXLEN-1)) { printf("You should never see this but I couldn't read 5 bytes from dev/urandom.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } } else { printf("You should never see this but I couldn't open /dev/urandom for reading.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { power = (1 << (resetpower-1)) -1; } else { power = 0; } if ((setsize > MINLEN) && (setsize < MAXLEN)) { if ((!zeroflag) && (!resetflag)) { power = 0; resetpower = 0; } ecbs64setsize(setsize); } else { ecbs64setsize(lfsralen); setsize = 0; } } if (readflag) { if ((setsize > MINLEN) && (setsize < MAXLEN)) { if (!resetflag) { power = 0; resetpower = 0; } ecbs64setsize(setsize); } } /* * This is where we seed from the user's CLI inputs. There * is nothing but user input used here so this is always * repeatable exacty. Notice that we are starting out with LFSR data * read in from the user seed input, but taps and lfsrlen are still * set to default. NOTE I call it lfsra in case there is an lfsrb or lfsrc. * If no readflag, we are clear to use the input seed data. If readflag is * set, then everything is already initialized. * First thing is check if we have wrapped around the LFSR MAXLEN. * If we have.then the random length selection can be anything, unless * the user specified a length. But if the totalseedchars is less than * MAXLEN-1, and no length is specified, then use the number of seed chars * as the length. This simply provides an easy way to implicitly set the * length. I could set a random length, always smaller than the input count, * but I don't see the point. But, since we can have resetflag, we always * initially call ecbs64setsize with MAXLEN-1. This will cause it to cycle * through the full length, regardless of user selected size. That fills * in the unused lfsra elements with values from the initial seed, * regardless how many bytes are provided. That means if we ever do * call ecbs64setsize, any new elements added will already have some * non initial value. * The user provided all the seed values on CLI. */ /* * If setsize is set, then it doesn't matter if user provided * CLI seed data or it was obtained by /dev/urandom, we just * do this stuff either way. */ if ((setsize > MINLEN) && (setsize < MAXLEN) && (!readflag)) { if ((!resetflag) && (!zeroflag) ) { power = 0; resetpower = 0; } ecbs64setsize(MAXLEN-1); adder1 += ecbs64(); adder2 += ecbs64(); adder3 += ecbs64(); adder4 += ecbs64(); ecbs64setsize(setsize); } else { /* * If setsize is NOT set, then if totalchars > 0, then that means * user provided seed data. If either readflag or zeroflag is set * then just ignore any user seed data. It would get wiped out * by zeroflag anyway, and readflag means we already have everything. */ if ((totalseedchars > 0) && (!readflag) && (!zeroflag)) { if (totalseedchars < (MINLEN+1)) { ecbs64setsize(MAXLEN-1); adder1 += ecbs64(); adder2 += ecbs64(); adder3 += ecbs64(); adder4 += ecbs64(); ecbs64setsize(MINLEN+1); } if (totalseedchars >= (MAXLEN-1)) { ecbs64setsize(MAXLEN-1); adder1 += ecbs64(); adder2 += ecbs64(); adder3 += ecbs64(); adder4 += ecbs64(); ecbs64setsize(MAXLEN-1); } if ((totalseedchars < (MAXLEN-1)) && (totalseedchars > (MINLEN+1))) { ecbs64setsize(MAXLEN-1); adder1 += ecbs64(); adder2 += ecbs64(); adder3 += ecbs64(); adder4 += ecbs64(); ecbs64setsize(totalseedchars); } } } /* Zero out everything except lfsralen and maxtap, and set taps to 0-7. */ if (zeroflag) { if (zeroflag == 1) { tapa1 = 0; tapa2 = 1; tapa3 = 2; tapa4 = 3; tapa5 = 4; tapa6 = 5; tapa7 = 6; tapa8 = 7; } for (i=0; i<(MAXLEN-1); i++) { lfsra[i] = 0; } adder1 = 0; adder2 = 0; adder3 = 0; adder4 = 0; if ((setsize > MINLEN) && (setsize < MAXLEN) && ((zeroflag >1) || (resetflag))) { lfsralen = setsize; } else { lfsralen = (MINLEN+1); } maxtap = lfsralen - 1; if ((!resetflag) || (zeroflag < 1)) { power = 0; resetpower = 0; } } /* * Regardless how we seeded or for what purpose, the entropyflag says * add entropy to make it unpredictable and unrepeatable. This means we * have to call the ecbs64entropy() function at least once, and cycle * lfsralen times to guarantee we start with unpredictable output, * regardless of seed. This randomizes any seed so the output cannot * ever be reproduced. Also, this means ecbs64entropy() must be called * periodically. We just call ecbs64entropyI) every time we call * ecbs64setsize(). Because ecbs64setsize is randomized, entropy calls * are also randomized but get mixed by the ecbs64setsize() which * immediately follows. * NOTE: Since we initialize the seconds and lastseconds and lastns * and ns variables to zero, the first call uses 0 for both values * on the first call. This does nothing. The first call merely populates * the lastseconds and lastns variables which are used for the update * before they themselves are updated. This means we always have to make * two initial calls in order to cause immediate effects. See the * ecbs64.readme file for discussion of the gettime() method. */ if (entropyflag) { ecbs64entropy(); ecbs64entropy(); ecbs64setsize(lfsralen); } /* fprintf(stderr, "INITFINIT resetpower %d power = %llu lfsralen %d setsize %d entropyflag = %d\n", resetpower, power, lfsralen, setsize, entropyflag); fprintf(stderr, "INITFINIT seconds %llu lastseconds = %llu ns %llu lastns %llu\n", seconds, lastseconds, ns, lastns); */ /* * Finally we are all done with initialization. Check for dump commands. * If dump == 1, just the adders, length and taps are printed. If > 1, * then the LFSR elements are also dumped. Logstate does the same as * dumpsate except to a logfile. */ if (dump) { if (logging) { logstate(); } dumpstate(); return(0); } /* * The value 3 is used so that I know where it was called from. If I add * logstate commands for testing, I can use different numbers to identify * the calling code. */ dump = 3; if (logging) { logstate(); } /* These are only used for the toy encrypt and decrypt functions. */ unsigned char tmp1 = 0; unsigned char tmp2 = 0; if (constantflag) { if (encrypt) { lastchar = adder3; readcount = fread(seedbuffer, 1, MAXINP, stdin); while (readcount > 0) { for (i=0; i 0) { for (i=0; i 0) { for (i=0; i 0) { for (i=0; ist_size; if (logfilesize < 1) { printf("Error: problem with file spec logfile\n"); } logfile = fopen(logfilename, "a"); sprintf(line, "%s %s", filename, timestring); fputs(line, logfile); sprintf(line, "MAXINP = %6u ( Input buffer size)\n", MAXINP); fputs(line, logfile); sprintf(line, "MAXOUT = %6u (Output buffer size)\n", MAXOUT); fputs(line, logfile); sprintf(line, "MAXLEN - 1 = %6u (Maximum LFSR size)\n", MAXLEN-1); fputs(line, logfile) ; sprintf(line, "MINLEN + 1 = %6u (Minimum LFSR size)\n", MINLEN+1); fputs(line, logfile); sprintf(line, "constantflag = %d constant1 = %llu constant2 = %llu\n", constantflag, constant1, constant2); fputs(line, logfile); sprintf(line, "totalseedchars = %u cripple = %u tapswap = %u dump = %u\n", totalseedchars, cripple, tapswap, dump); fputs(line, logfile); sprintf(line, "adders = %llu %llu %llu %llu resetpower = %u\n", adder1, adder2, adder3, adder4, resetpower); fputs(line, logfile); if (dump) { sprintf(line, "lfsralen = %d shift = %d\n", lfsralen, shift); fputs(line, logfile); sprintf(line, "tapa1 = %d\n", tapa1); fputs(line, logfile); sprintf(line, "tapa2 = %d\n", tapa2); fputs(line, logfile); sprintf(line, "tapa3 = %d\n", tapa3); fputs(line, logfile); sprintf(line, "tapa4 = %d\n", tapa4); fputs(line, logfile); sprintf(line, "tapa5 = %d\n", tapa5); fputs(line, logfile); sprintf(line, "tapa6 = %d\n", tapa6); fputs(line, logfile); sprintf(line, "tapa7 = %d\n", tapa7); fputs(line, logfile); sprintf(line, "tapa8 = %d\n", tapa8); fputs(line, logfile); } if (dump > 1) { for (i=0; i MINLEN) && (thenewsize < MAXLEN)) { newsize = thenewsize; busy = 1; /* Now we assign the taps array their index values to be shuffled */ for (i=0; i= newsize */ x = 1; while (x <= (newsize)) { x <<= 1; } x -= 1; /* Now swap the tmp taps array for a few cycles */ /* We are still using the previous lfsra and taps and adders */ for (i=0; i<(MAXLEN+lfsralen); i++) { swapa = ecbs64() & x; swapb = ecbs64() & x; while (swapa >= newsize) { swapa = (swapa + ecbs64()) & x; } while (swapb >= newsize) { swapb = (swapb + ecbs64()) & x; } tmp = taps[swapa]; taps[swapa] = taps[swapb]; taps[swapb] = tmp; } /* Still setting things with the values collected above. */ tapa1 = taps[0]; tapa2 = taps[1]; tapa3 = taps[2]; tapa4 = taps[3]; tapa5 = taps[4]; tapa6 = taps[5]; tapa7 = taps[6]; tapa8 = taps[7]; lfsralen = newsize; maxtap = lfsralen - 1; for (i=0; i<(MAXLEN+lfsralen); i++) { swapa = ecbs64() & x; swapb = ecbs64() & x; while (swapa >= newsize) { swapa = (swapa + ecbs64()) & x; } while (swapb >= newsize) { swapb = (swapb + ecbs64()) & x; } tmp = taps[swapa]; taps[swapa] = taps[swapb]; taps[swapb] = tmp; } tapa1 = taps[0]; tapa2 = taps[1]; tapa3 = taps[2]; tapa4 = taps[3]; tapa5 = taps[4]; tapa6 = taps[5]; tapa7 = taps[6]; tapa8 = taps[7]; busy = 0; } /*fprintf(stderr, "SETSIZE RETURNING lfsralen %d\n", lfsralen);*/ } /* END ecbs64setsize */ /* * This is the main PRNG. It requires the adders to work, but even so * may run into short periods. Short is relative. I don't know * how short they might be because I can't find them in a reasonable * time. But I strongly suspect they exist. But regardless, the * adders guarantee minimum 2**32 period because they essentially * amount to stepping into a different cycle each time. So if you * do hit a short cyle, you'll most likely be out of it on the next * call. If not, probably the next one, but in any case, sooner or * later, and thats not more than a few calls at most. * */ /* function implementation */ unsigned long long int ecbs64 (void) { unsigned long long int swap; unsigned long long int tmp; --tapa1; if (tapa1 > maxtap) { tapa1 = maxtap; } --tapa2; if (tapa2 > maxtap) { tapa2 = maxtap; } --tapa3; if (tapa3 > maxtap) { tapa3 = maxtap; } --tapa4; if (tapa4 > maxtap) { tapa4 = maxtap; } --tapa5; if (tapa5 > maxtap) { tapa5 = maxtap; } --tapa6; if (tapa6 > maxtap) { tapa6 = maxtap; } --tapa7; if (tapa7 > maxtap) { tapa7 = maxtap; } --tapa8; if (tapa8 > maxtap) { tapa8 = maxtap; } switch (cripple) { case 0: ++adder1; if (adder1 == 0) { ++adder2; if (adder2 == 0) { ++adder3; if (adder3 == 0) { ++adder4; } } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; lfsra[tapa7] += adder4; break; case 1: ++adder1; if (adder1 == 0) { ++adder2; if (adder3 == 0) { ++adder3; } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; break; case 2: ++adder1; if (adder1 == 0) { ++adder2; } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; break; case 3: ++adder1; lfsra[tapa2] += adder1; break; case 4: break; default: break; } lfsra[tapa1] = ((lfsra[tapa1] ^ (lfsra[tapa2] * (lfsra[tapa3]|1))) + lfsra[tapa4]); --shift; if (shift == 0) { shift = 63; } lfsra[tapa1] = ((lfsra[tapa1] >> shift) | (lfsra[tapa1] << (64-shift))); if (tapswap) { swap = (lfsra[tapa2] ^ lfsra[tapa3]) & 7; switch (swap) { case 0: tmp = tapa1; tapa1 = tapa2; tapa2 = tmp; break; case 1: tmp = tapa2; tapa2 = tapa3; tapa3 = tmp; break; case 2: tmp = tapa3; tapa3 = tapa4; tapa4 = tmp; break; case 3: tmp = tapa4; tapa4 = tapa5; tapa5 = tmp; break; case 4: tmp = tapa5; tapa5 = tapa6; tapa6 = tmp; break; case 5: tmp = tapa6; tapa6 = tapa7; tapa7 = tmp; break; case 6: tmp = tapa7; tapa7 = tapa8; tapa8 = tmp; break; case 7: tmp = tapa8; tapa8 = tapa1; tapa1 = tmp; break; default: break; } } lfsra[tapa5] = ((lfsra[tapa5] ^ (lfsra[tapa6] * (lfsra[tapa7]|1))) + lfsra[tapa8]); --shift; if (shift == 0) { shift = 63; } lfsra[tapa5] = ((lfsra[tapa5] >> shift) | (lfsra[tapa5] << (64-shift))); /* fprintf(stderr, "ECBS restpower = %d power = %lu lfsralen = %d lfsra[tapa1] %lu lfsra[tapa2] = %lu \n", resetpower, power, lfsralen, lfsra[tapa1], lfsra[tapa2] ); */ if (resetpower) { if ((lfsra[tapa2] & power) == power) { if (entropyflag) { ecbs64entropy(); } setsize = ( lfsra[tapa8] & (MAXLEN-1) ); setsize |= (MAXLEN/2); ecbs64setsize(setsize); } } return(lfsra[tapa1] ^ lfsra[tapa5]); } /* END ecbs64 */ /* function implementation */ unsigned long long int ecbs64const (void) { unsigned long long int swap; unsigned long long int tmp; --tapa1; if (tapa1 > maxtap) { tapa1 = maxtap; } --tapa2; if (tapa2 > maxtap) { tapa2 = maxtap; } --tapa3; if (tapa3 > maxtap) { tapa3 = maxtap; } --tapa4; if (tapa4 > maxtap) { tapa4 = maxtap; } --tapa5; if (tapa5 > maxtap) { tapa5 = maxtap; } --tapa6; if (tapa6 > maxtap) { tapa6 = maxtap; } --tapa7; if (tapa7 > maxtap) { tapa7 = maxtap; } --tapa8; if (tapa8 > maxtap) { tapa8 = maxtap; } switch (cripple) { case 0: ++adder1; if (adder1 == 0) { ++adder2; if (adder2 == 0) { ++adder3; if (adder3 == 0) { ++adder4; } } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; lfsra[tapa7] += adder4; break; case 1: ++adder1; if (adder1 == 0) { ++adder2; if (adder3 == 0) { ++adder3; } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; break; case 2: ++adder1; if (adder1 == 0) { ++adder2; } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; break; case 3: ++adder1; lfsra[tapa2] += adder1; break; case 4: break; default: break; } lfsra[tapa1] += constant1; --shift; if (shift == 0) { shift = 63; } lfsra[tapa1] = ((lfsra[tapa1] >> shift) | (lfsra[tapa1] << (64-shift))); if (tapswap) { swap = (lfsra[tapa2] ^ lfsra[tapa3]) & 7; switch (swap) { case 0: tmp = tapa1; tapa1 = tapa2; tapa2 = tmp; break; case 1: tmp = tapa2; tapa2 = tapa3; tapa3 = tmp; break; case 2: tmp = tapa3; tapa3 = tapa4; tapa4 = tmp; break; case 3: tmp = tapa4; tapa4 = tapa5; tapa5 = tmp; break; case 4: tmp = tapa5; tapa5 = tapa6; tapa6 = tmp; break; case 5: tmp = tapa6; tapa6 = tapa7; tapa7 = tmp; break; case 6: tmp = tapa7; tapa7 = tapa8; tapa8 = tmp; break; case 7: tmp = tapa8; tapa8 = tapa1; tapa1 = tmp; break; default: break; } } lfsra[tapa5] += constant2; --shift; if (shift == 0) { shift = 63; } lfsra[tapa5] = ((lfsra[tapa5] >> shift) | (lfsra[tapa5] << (64-shift))); /* fprintf(stderr, "reset = %d restpower = %d power = %d lfsralen = %d lfsra[tapa1] %d lfsra[tapa2] = %d \n", reset, resetpower, power, lfsralen, lfsra[tapa1], lfsra[tapa2] ); */ if (resetpower) { if ((lfsra[tapa2] & power) == power) { if (entropyflag) { ecbs64entropy(); } setsize = ( lfsra[tapa8] & (MAXLEN-1) ); setsize |= (MAXLEN/2); ecbs64setsize(setsize); } } return(lfsra[tapa1] ^ lfsra[tapa5]); } /* END ecbs64const */ void singlestepinit(void) { int pflag = 0; int j; fprintf(stdout, " %llu %llu %llu %llu RETVAL INIT A\n", adder1, adder2, adder3, adder4); for (j=0; j