/* * cryrand - cryptographically strong pseudo-random number generator library */ /* * Copyright (c) 1993 by Landon Curt Noll. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright, this permission notice and text * this comment, and the disclaimer below appear in all of the following: * * supporting documentation * source copies * source works derived from this source * binaries derived from this source or from derived source * * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * chongo was here /\../\ */ /* * These routines are written in the calc language. At the time of this * notice, calc was at version 1.24.7 (We refer to calc, as in the C * program, not the Emacs subsystem). * * Calc is available by anonymous ftp from ftp.uu.net (137.39.1.9) * under the directory /pub/calc. * * If you can't get calc any other way, Email a request to my Email * address as shown below. * * Comments, suggestions, bug fixes and questions about these routines * are welcome. Send Email to the address given below. * * Happy bit twiddling, * * Landon Curt Noll * * chongo@toad.com * ...!{pyramid,sun,uunet}!hoptoad!chongo */ /* * AN OVERVIEW OF THE FUNCTIONS: * * This calc library contains several pseudo-random number generators: * * additive 55: * * a55rand - external interface to the additive 55 generator * sa55rand - seed the additive 55 generator * * This is a generator based on the additive 55 generator as * described in Knuth's "The Art of Computer Programming - * Seminumerical Algorithms", vol 2, 2nd edition (1981), * Section 3.2.2, page 27, Algorithm A. * * The period and other properties of this generator make it very * useful to 'seed' other generators. * * This generator is used by other other generators to produce * various internal values. In fact, the lower 64 bits of seed * given to other other generators is passed to sa55rand(). * * shuffle: * * shufrand - generate a pseudo-random value via a shuffle process * sshufrand - seed the shufrand generator * rand - generate a pseudo-random value over a given range * srand - seed the random stream generator * * This is a generator based on the shuffle generator as described in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B. * * The shuffle generator is fast and serves as a fairly good standard * pseudo-random generator. * * The shuffle generator is feed random values by the additive 55 * generator via a55rand(). Calling a55rand() or sa55rand() will * affect the shuffle generator output. * * The rand function is really another interface to the shuffle * generator. Unlike shufrand(), rand() can return a value of any * given size. The value returned by rand() may be confined to * either a half open [0,a) (0 <= value < a) or closed interval * [a,b] (a <= value <= b). By default, a 64 bit value is returned. * * Calling srand() simply calls sshufrand() with the same seed. * * crypto: * * cryrand - produce a cryptographically strong pseudo-random number * scryrand - seed the crypto generator * random - produce a cryptographically strong pseudo-random number * over a given range * srandom - seed random * * This generator is described in the papers: * * Blum, Blum, and Shub, "Comparison of Two Pseudorandom Number * Generators", in Chaum, D. et. al., "Advances in Cryptology: * Proceedings Crypto 82", pp. 61-79, Plenum Press, 1983. * * "Probabilistic Encryption", Journal of Computer & System * Sciences 28, pp. 270-299. * * We also refer to this generator as the 'Blum' generator. * * This generator is considered 'strong' in that it passes all * polynomial-time statistical tests. This means that there * is no statistical test, which runs in polynomial time, that * can distinguish the crypto generator from a truly random source. * * The crypto generator is not as fast as most generators, though * it is not painfully slow either. * * One may fully seed this generator via scryrand(). Calling * scryrand() with 1 or 3 arguments will result in the additive * 55 generator being seeded with the same seed. Calling * scryrand() with 4 arguments, where the first argument * is >= 0 will also result in the additive 55 generator * being seeded with the same seed. * * The random() generator is really another interface to the * crypto generator. Unlike cryrand(), random() can return a * value confined to either a half open (0 <= value < a) or closed * interval (a <= value <= b). By default, a 64 bit value is * returned. * * Calling srandom() simply calls scryrand(seed). The additive * 55 generator will be seeded with the same seed. * * All generators come already seeded with precomputed initial constants. * Thus, it is not required to seed a generator before using it. * * Using a seed of '0' will reload generators with their initial states. * In the case of scryrand(), lengths of -1 must also be supplied. * * sa55rand(0) * sshufrand(0) * srand(0) * scryrand(0,-1,-1) * srandom(0) * scryrand(-1,ip,iq,ir) * * All of the above 'seed 0' calls are fairly fast. In fact, passing * seeding with a non-zero seed, in the above cases, where seed is * not excessively large (many bits long), is also reasonably fast. * The 4 arg scryrand() call is fairly fast because no checking is * performed on the 'ip', 'iq', or 'ir' values. * * A call of scryrand(seed,len1,len2), with len1,len2 > 4, (3 args) * is a somewhat slow as the length args increase. This type of * call selects 2 primes that are used internally by the crypto * generator. A call of scryrand(seed,ip,iq,ir) where seed >= 0 * is as slow as the 3 arg case. See scryrand() for more information. * * A call of scryrand() (no args) may be used to quickly change the * internal state of the crypto and random generators. Only one major * internal crypto generator value (a quadratic residue) is randomly * selected via the additive 55 generator. The other 2 major internal * values (the 2 Blum primes) are preserved. In this form, the additive * 55 is not seeded. * * Calling scryrand() with 1 or 3 args, or calling srandom() will leave * the additive 55 generator in a seeded state as if sa55rand(seed) has * been called. Calling scryrand() with 4 args, where the first arg is * >0 will also leave the additive 55 generator in the same scryrand(seed) * state. Calling scryrand() with no args will not seed the additive * 55 generator before or afterwards, however the additive 55 and shuffle * generators will be changed as a side effect of that call. * * The states of all generators (additive 55, shuffle and crypto) can be * saved and restored via the randstate() function. Saving the state just * after * seeding a generator and restoring it later as a very fast way * to reseed a generator. * * As a bonus, the function 'nxtprime' is provided to produce a probable * prime number. * * TRUTH IN ADVERTISING: * * The word 'probable', in reference to the nxtprime() function, is used * because of an extremely extremely small chance that a composite (a * non-prime) may be returned. In no cases will a prime be skipped. * For our purposes, this is sufficient as the chance of returning a * composite is much smaller than the chance that a hardware glitch * will cause nxtprime() to return a bogus result. * * Another "truth in advertising" issue is the use of the term * 'pseudo-random'. All deterministic generators are pseudo random. * This is opposed to true random generators based on some special * physical device. * * The crypto generator is 'pseudo-random'. There is no statistical * test, which runs in polynomial time, that can distinguish the crypto * generator from a truly random source. * * A final "truth in advertising" issue deals with how the magic numbers * found in this library were generated. Detains can be found in the * various functions, while a overview can be found in the SOURCE FOR * MAGIC NUMBERS section below. * **** * * ON THE GENERATORS: * * The additive 55 generator has a good period, and is fast. It is * reasonable as generators go, though there are better ones available. * We use it in seeding the crypto generator as its period and * other statistical properties are good enough for our purposes. * * This shuffle generator has a very good period, and is fast. It is * fairly good as generators go, and is better than the additive 55 * generator. Casual direct use of the shuffle generator may be * acceptable. Because of this, the interface to the shuffle generator, * but not the additive 55 generator, is advertised when this file is * loaded. * * The shuffle generator functions, shufrand() and rand() use the same * seed and tables. The shuffle generator shuffles the values produced * by the additive 55 generator. Calling or seeding the additive 55 * generator will affect the output of the shuffle generator. * * The crypto generator is the best generator in this package. It * produces a cryptographically strong pseudo-random bit sequence. * Internally, a fixed number of bits are generated after each * generator iteration. Any unused bits are saved for the next call * to the generator. The crypto generator is not too slow, though * seeding the generator from scratch is slow. Shortcuts and * pre-computer seeds have been provided for this reason. Use of * crypto should be more than acceptable for many applications. * * The crypto seed is in 4 parts, the additive 55 seed (lower 64 * bits of seed), the shuffle seed (all but the lower 64 bits of * seed), and two lengths. The two lengths specifies the minimum * bit size of two primes used internal to the crypto generator. * Not specifying the lengths, or using -1 will cause crypto to * use the default minimum lengths of 248 and 264 bits, respectively. * * The random() function just another interface to the crypto * generator. Like rand(), random() provides an interval capability * (closed or open) as well as a 64 bit default return value. * The random() function as good as crypto, and produces numbers * that are equally cryptographically strong. One may use the * seed functions srandom() or scryrand() for either the random() * or cryrand() functions. * * The seed for all of the generators may be of any size. Only the * lower 64 bits of seed affect the additive 55 generator. Bits * beyond the lower 64 bits affect the shuffle generators. Excessively * large values of seed will result in increased memory usage as * well as a larger seed time for the shuffle and crypto generators. * See REGARDING SEEDS below, for more information. * * One may save and restore the state of all generators via the * randstate() function. * **** * * REGARDING SEEDS: * * Because the generators are interrelated, seeding one generator * will directly or indirectly affect the other generators. Seeding * the shuffle generator seeds the additive 55 generator. Seeding * the crypto generator seeds the shuffle generator. * * The seed of '0' implies that a generator should be seeded back * to its initial default state. * * For the moment, seeds < -1 are reserved for future use. The * value of -1 is used as a special indicator to the fourth form * of scryrand(), and it not a real seed. * * A seed may be of any size. The additive 55 generator uses only * the lower 64 bits, while the shuffle generator uses bytes beyond * the lower 64 bits. * * To help make the generator produced by seed S, significantly * different from S+1, seeds are scrambled prior to use. The * function randreseed64() maps [0,2^64) into [0,2^64) in a 1-to-1 * and onto fashion. * * The purpose of the randreseed64() is not to add security. It * simply helps remove the human perception of the relationship * between the seed and the production of the generator. * * The randreseed64() process does not reduce the security of the * generators. Every seed is converted into a different unique seed. * No seed is ignored or favored. * * There is no limit on the size of a seed. On the other hand, * extremely large seeds require large tables and long seed times. * Using a seed in the range of [2^64, 2^64 * 128!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 215 digits, or 64 to * 780 bits long. * **** * * SOURCE OF MAGIC NUMBERS: * * Most of the magic constants used on this library ultimately are * based on the Rand book of random numbers. The Rand book contains * 10^6 decimal digits, generated by a physical process. This book, * produced by the Rand corporation in the 1950's is considered * a standard against which other generators may be measured. * * The Rand book of numbers was groups into groups of 20 digits. * The first 55 groups < 2^64 were used to initialize add55_init_tbl. * The size of 20 digits was used because 2^64 is 20 digits long. * The restriction of < 2^64 was used to prevent modulus biasing. * (see the note on modulus biasing in rand()). * * The additive 55 generator during seeding is used 128 times to help * remove the initial seed state from the initial values produced. * The loop count of 128 was a power of 2 that permits each of the * 55 table entries to be processed at least twice. * * The function, randreseed64(), uses 4 primes to scramble 64 bits * into 64 bits. These primes were also extracted from the Rand * book of numbers. See sshufrand() for details. * * The default shuffle table size of 128 entries is the power of 2 * that is longer than the 100 entries recommended by Knuth for * the shuffle algorithm (see the text cited in shufrand()). * We use a power of 2 shuffle table length so that the shuffle * process can select a table entry from a new additive 55 value * by extracting its top most bits. * * The quadratic residue search performed by cryres() starts at * a value that is in the interval [2^sqrpow,n-3), where 2^sqrpow * is the first power of 2 > n^(3/4) and n = p*q. We look at 1009 * random numbers in this interval for a quadratic residue. If * none are found, sqrpow is decremented by 1 if sqrpow > 2. * In practice, decrementing sqrpow never happens. * * The use of n^(3/4) insures that the quadratic residue is * large, but not too large. We want to avoid residues that are * near the square root of 'n', and are nearly 'n' itself (hence * the n-3 upper limit) as such residues are trivial or semi-trivial. * * The '1009' trials is simply an attempt to look for a while before * picking a new range. The number '1009' comes from the first 4 * digits of the rand book of numbers. * * Keeping sqrpow > 2 means that we do not look for quadratic * residues that are below 4. This is in keeping with the * n-3 in the [2^sqrpow,n-3) interval. * * The final magic numbers: '248' and '264' are the exponents the * largest powers of 2 that are < the two default Blum primes 'p' * and 'q' used by the crypto generator. The values of '248' and * '264' implies that the product n=p*q > 2^512. Each iteration * of the crypto generator produces log2(log2(n=p*q)) random bits. * The crypto generator is the most efficient when n is slightly > * 2^(2^b). The product n > 2^(2^9)) produces 9 bits as efficiently * as possible under the crypto generator process. * * Not being able to factor 'n=p*q' into 'p' and 'q' does not directly * improve the crypto generator. On the other hand, it can't hurt. * The two len values differ slightly to avoid factorization attacks * that work on numbers that are a perfect square, or where the two * primes are nearly the same. I elected to have the sizes differ * by 3% of the product size. The difference between '248' and * '264', is '16', which is ~3.125% of '512'. Now 3% of '512' is * '~15.36', and the next largest whole number is '16'. * * The product n=p*q > 2^512 implies a product if at least 155 digits. * A product of two primes that is at least 155 digits is slightly * beyond Number Theory and computer power of Nov 1992, though this * will likely change in the future. * * Again, the ability (or lack thereof) to factor 'n=p*q' does not * directly relate to the strength of the crypto generator. We * selected n=p*q > 2^512 mainly because '512 was a power of 2 and * only slightly because it is up in the range where it is difficult * to factor. * **** * * FOR THE PARANOID: * * The truly paranoid might suggest that my claims in the MAGIC NUMBERS * section are a lie intended to entrap people. Well they are not, but * you need not take my word for it. * * The random numbers from the Rand book of random numbers can be * verified by anyone who obtains the book. As these numbers were * created before I (Landon Curt Noll) was born (you can look up * my birth record if you want), I claim to have no possible influence * on their generation. * * There is a very slight chance that the electronic copy of the * Rand book that I was given access to differs from the printed text. * I am willing to provide access to this electronic copy should * anyone wants to compare it to the printed text. * * One might object to the complexity of the seed scramble/mapping * via the randreseed64() function. The randreseed64() function maps: * * 1 ==> 4967126403401436567 * * calling srand(1) with the randreseed64() process would be the same * as calling srand(4967126403401436567) without it. No extra security * is gained or reduced by using the randreseed64() process. The meaning * of seeds are exchanged, but not lost or favored (used by more than * one input seed). * * One could take issue with my selection of the default sizes '248' * and '264'. As far as I know, 155 digits (512 bits) is beyond the * state of the art of Number Theory and Computation as of 01 Sep 92. * It will likely be true that 155 digit products of two primes could * come within reach in the next few years, but so what? If you are * truly paranoid, why would you want to use the default seed, which * is well known? * * The paranoid today might consider using the lengths of at least '345' * and '325' will produce a product of two primes that is 202 digits. * (the 2nd and 3rd args of scryrand > 345 & >325 respectively) Factoring * 200+ digit product of two primes is well beyond the current hopes of * Number Theory and Computer power, though even this limit may be passed * someday. * * If all the above fails to pacify the truly paranoid, then one may * select by some independent means, 2 Blum primes (primes mod 4 == 3, * p < q), and a quadratic residue if p*q. Then by calling: * * scryrand(-1, p, q, r) * * and then calling cryrand() or random(), one may bypass all magic * numbers and use the pure generator. * * Note that randstate() may also be used by the truly paranoid. * Even though it holds state for the other generators, their states * are independent. * **** * * GOALS: * * The goals of this package are: * * all magic numbers are explained * * I distrust systems with constants (magic numbers) and tables * that have no justification (e.g., DES). I believe that I have * done my best to justify all of the magic numbers used. * * full documentation * * You have this source file, plus background publications, * what more could you ask? * * large selection of seeds * * Seeds are not limited to a small number of bits. A seed * may be of any size. * * the strength of the generators may be tuned to meet the application need * * By using the appropriate seed arguments, one may increase * the strength of the generator to suit the need of the * application. One does not have just a few levels. * * This calc lib file is intended for demonstration purposes. Writing * a C program (with possible assembly or libmp assist) would produce * a faster generator. * * Even though I have done my best to implement a good system, you still * must use these routines your own risk. * * Share and enjoy! :-) */ /* * These constants are used by all of the generators in various direct and * indirect forms. */ cry_seed = 0; /* master seed */ cry_mask = 0xffffffffffffffff; /* 64 bit work mask */ /* * Initial magic values for the additive 55 generator - used by sa55rand() * * These values were generated from the Rand book of random numbers. * In groups of 20 digits, we took the first 55 groups < 2^64. */ mat add55_init_tbl[55]; add55_init_tbl[0] = 10097325337652013586; add55_init_tbl[1] = 8422689531964509303; add55_init_tbl[2] = 9376707153831131165; add55_init_tbl[3] = 12807999708015736147; add55_init_tbl[4] = 12171768336606574717; add55_init_tbl[5] = 2051656926866574818; add55_init_tbl[6] = 3529647783580834282; add55_init_tbl[7] = 13746700781847540610; add55_init_tbl[8] = 17468509505804776974; add55_init_tbl[9] = 14385537637435099817; add55_init_tbl[10] = 14225685144642756788; add55_init_tbl[11] = 11100020401286074697; add55_init_tbl[12] = 7207317906119690446; add55_init_tbl[13] = 15474452669527079953; add55_init_tbl[14] = 16868487670307112059; add55_init_tbl[15] = 4493524947524633824; add55_init_tbl[16] = 13021248927856520106; add55_init_tbl[17] = 15956600001874392423; add55_init_tbl[18] = 1758753794041921585; add55_init_tbl[19] = 1540354560501451176; add55_init_tbl[20] = 5335129695612719255; add55_init_tbl[21] = 9973334408846123356; add55_init_tbl[22] = 2295368703230757546; add55_init_tbl[23] = 15020099946907494138; add55_init_tbl[24] = 10518216150184876938; add55_init_tbl[25] = 9188200973282539527; add55_init_tbl[26] = 4220863048338987374; add55_init_tbl[27] = 682273982071453295; add55_init_tbl[28] = 7706178130835869910; add55_init_tbl[29] = 4618975533122308420; add55_init_tbl[30] = 397583911260717646; add55_init_tbl[31] = 5686731560708285046; add55_init_tbl[32] = 10123916228549657560; add55_init_tbl[33] = 1304775865627110086; add55_init_tbl[34] = 15501295782182641134; add55_init_tbl[35] = 3061180729620744156; add55_init_tbl[36] = 6958929830512809719; add55_init_tbl[37] = 10850627469959910507; add55_init_tbl[38] = 13499063195307571839; add55_init_tbl[39] = 6410193623982098952; add55_init_tbl[40] = 4111084083850807341; add55_init_tbl[41] = 17719042079595449953; add55_init_tbl[42] = 5462692006544395659; add55_init_tbl[43] = 18288274374963224041; add55_init_tbl[44] = 8337656769629990836; add55_init_tbl[45] = 7477446061798548911; add55_init_tbl[46] = 9815931464890815877; add55_init_tbl[47] = 6913451974267278601; add55_init_tbl[48] = 11883095286301198901; add55_init_tbl[49] = 14974403441045516019; add55_init_tbl[50] = 14210337129134237821; add55_init_tbl[51] = 12883973436502761184; add55_init_tbl[52] = 4285013921797415077; add55_init_tbl[53] = 16435915296724552670; add55_init_tbl[54] = 3742838738308012451; /* * additive 55 tables - used by a55rand() and sa55rand() */ add55_j = 23; /* the first walking table pointer */ add55_k = 54; /* the second walking table pointer */ add55_seed64 = 0; /* lower 64 bits of the reseeded seed */ mat add55_tbl[55]; /* additive 55 state table */ /* * cryobj - cryptographic pseudo-random state object */ obj cryobj { \ p, /* first Blum prime (prime 3 mod 4) */ \ q, /* second Blum prime (prime 3 mod 4) */ \ r, /* quadratic residue of n=p*q */ \ exp, /* used in computing crypto good bits */ \ left, /* bits unused from the last cryrand() call */ \ bitcnt, /* left contains bitcnt crypto good bits */ \ a55j, /* 1st additive 55 table pointer */ \ a55k, /* 2nd additive 55 table pointer */ \ seed, /* last seed set by sa55rand() or 0 */ \ shufy, /* Y (previous a55rand output for shuffle) */ \ shufsz, /* size of the shuffle table */ \ shuftbl, /* a matrix of shufsz entries */ \ a55tbl /* additive 55 generator state table */ \ } /* * initial cryptographic pseudo-random values - used by scryrand() * * These values are what the crypto generator is initialized with * with this library first read. These values may be reproduced the * hard way by calling scryrand(0,248,264) or scryrand(0,-1,-1). * * We will build up these values a piece at a time to avoid long lines * that are difficult to send via Email. */ /* p, first Blum prime */ cryrand_init_p = 0x1aa9e726a735044; cryrand_init_p <<= 200; cryrand_init_p |= 0x73b7457c5297122310880fcbfa8d4e38380a00396d533300bb; /* q, second Blum prime */ cryrand_init_q = 0xa62ee0481aa12059c3; cryrand_init_q <<= 200; cryrand_init_q |= 0x79ef44e72ff58ea70cacabbe9d264a0b16db72117d96f77e17; /* quadratic residue of n=p*q */ cryrand_init_r = 0x3d214853f9a5bb4b12f467c9052129a9; cryrand_init_r <<= 200; cryrand_init_r |= 0xd215cc6b3c2eae8c7090591b16d8044a886b3c6a58759b1a07; cryrand_init_r <<= 200; cryrand_init_r |= 0x2b50a914b42e1b6f9703be86742837c4bc637804c2dc668c5b; /* * cryptographic pseudo-random values - used by cryrand() and scryrand() */ /* p, first Blum prime */ cryrand_p = cryrand_init_p; /* q, second Blum prime */ cryrand_q = cryrand_init_q; /* n = p*q */ cryrand_n = cryrand_p*cryrand_q; /* quad residue of n */ cryrand_r = cryrand_init_r; /* this cryrand() running exp used in computing crypto good bits */ cryrand_exp = cryrand_r; /* good crypto bits unused from the last cryrand() call */ cryrand_left = 0; /* the value cryrand_left contains cryrand_bitcnt crypto good bits */ cryrand_bitcnt = 0; /* * shufrand - shuffle generator constants */ shuf_size = 128; /* entries in shuffle table */ shuf_shift = (64-highbit(shuf_size)); /* shift a55 value to get tbl indx */ global shuf_y; /* Y value (previous output) */ mat shuf_tbl[shuf_size]; /* shuffle state table */ /* * products of consecutive primes - used by nxtprime() * * We compute these products now to avoid recalculating them on each call. * These values help weed out numbers that have a prime factor < 1000. */ nxtprime_pfact10 = pfact(10); nxtprime_pfact100 = pfact(100)/nxtprime_pfact10; nxtprime_pfact1000 = pfact(1000)/nxtprime_pfact100; /* * a55rand - additive 55 pseudo-random number generator * * returns: * A number in the half open interval [0,2^64) * * This function implements the additive 55 pseudo-random number generator. * * This is a generator based on the additive 55 generator as described in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.2.2, page 27, Algorithm A. * * This function is called from the shuffle generator function shufrand(). * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you are looking for a fast generator and do not need a crypto * strong generator, you should not use this generator. Use of * the shuffle generator functions shufrand() and rand() should * be considered instead. */ define a55rand() { local ret; /* the pseudo-random number to return */ /* generate the next value using the additive 55 generator method */ ret = add55_tbl[add55_k] + add55_tbl[add55_j]; ret &= cry_mask; add55_tbl[add55_k] = ret; /* post-process out data with the seed */ ret = xor(ret, add55_seed64); /* step the pointers */ --add55_j; if (add55_j < 0) { add55_j = 54; } --add55_k; if (add55_k < 0) { add55_k = 54; } /* return the new pseudo-random number */ return(ret); } /* * sa55rand - initialize the additive 55 pseudo-random generator * * given: * seed * * returns: * old_seed * * This function seeds the additive 55 pseudo-random generator. * * This is a generator based on the additive 55 generator as described in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.2.2, page 27, Algorithm A. * * Unlike Knuth's description, we will let a seed post process our data. * * We do not apply the seed processing to the additive 55 table * data as this would disturb its pseudo-random generator properties. * Instead, we xor the output with the low 64 bits of seed. * * If seed == 0: * * This function produces values in exactly the same way * described by Knuth. * * else: * * Each value produced is xor-ed by a 64 bit value. This value * is the result of randreseed64(rand), which produces a 64 * bit value. * * Anyone comfortable with seed == 0 should also be comfortable with * non-zero seeds. A non-zero seeded sequence will produce a values * that have the exact same pseudo-random properties as the algorithm * described by Knuth. I.e., the sequence, while different, is as good * (or bad) as the sequence produced by a seed of 0. * * This function updates both the cry_seed and a55_seed64 global values. * * This function is called from the shuffle generator seed function sshufrand(). * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you are looking for a fast generator and do not need a crypto * strong generator, you should not use this generator. Use of the * shuffle generator seed functions sshufrand() and srand() should * be considered instead. */ define sa55rand(seed) { local oldseed; /* previous seed */ local junk; /* discards the first few numbers */ local j; /* firewall */ if (!isint(seed)) { quit "bad arg: arg must be an integer"; } if (seed < 0) { quit "bad arg: seed < 0 is reserved for future use"; } /* misc table setup */ oldseed = cry_seed; /* remember the previous seed */ cry_seed = seed; /* save the new seed */ add55_tbl = add55_init_tbl; /* reload the table */ add55_j = 23; /* reset first walking table pointer */ add55_k = 54; /* reset second walking table pointer */ /* obtain our 64 bit xor seed */ add55_seed64 = randreseed64(seed); /* spin the pseudo-random number generator a while */ for (j=0; j < 128; ++j) { junk = a55rand(); } /* return the old seed */ return(oldseed); } /* * shufrand - implement the shuffle pseudo-random number generator * * returns: * A number in the half open interval [0,2^64) * * This function implements the shuffle number generator. * * This is a generator based on the shuffle generator as described in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B. * * The function rand() calls this function. * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you do not need a crypto strong pseudo-random generator * this function may very well serve your needs. */ define shufrand() { local j; /* table index to replace */ /* * obtain a new random value * determine the table entry to shuffle * shuffle out the value we will return */ shuf_y = shuf_tbl[j = (shuf_y >> shuf_shift)]; /* shuffle in the new random value */ shuf_tbl[j] = a55rand(); /* return the shuffled out value */ return (shuf_y); } /* * sshufrand - seed the shuffle pseudo-random generator * * given: * a seed * * returns: * the previous seed * * This function implements the shuffle number generator. * * This is a generator based on the shuffle generator as described in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B. * * The low 64 bits of seed are used by the additive 55 generator. * See the sa55rand() function for details. The remaining bits of seed * are used to perform an initial shuffle on the shuffle state table. * The size of the seed also determines the size of the shuffle table. * * The shuffle table size is always a power of 2, and is at least 128 * entries long. Let the table size be: * * shuf_size = 2^shuf_pow * * The number of ways one could shuffle that table is: * * (2^shuf_pow)! * * We select the smallest 'shuf_pow' (and thus the size of the shuffle table) * such that the following are true: * * (2^shuf_pow)! >= (seed / 2^64) and 2^shuf_pow >= 128 * * Given that we now have the table size of 'shuf_size', we must go about * loading the table and shuffling it. * * Loading is easy, we will generate random values via the additive 55 * generator (a55rand()) and load them into successive entries. * * We enumerate the (2^shuf_pow)! values via: * * shuf_seed = 2*(U[2] + 3*(U[3] + 4*(U[4] + ... * + (U[shuf_pow-1]*(shuf_pow-1)) ... ))) * 0 <= U[j] < j * * We swap the swap table entries shuf_tbl[U[j]] & shuf_tbl[j-1] for all * 1 < j < shuf_pow. * * We will convert 'seed / 2^64' into shuf_seed, by applying the 64 bit * scramble function on 64 bit chunks of 'seed / 2^64'. * * The function srand() calls this function. * * There is no limit on the size of a seed. On the other hand, * extremely large seeds require large tables and long seed times. * Using a seed in the range of [2^64, 2^64 * 128!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 215 digits long, or * 64 to 780 bits long. * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you do not need a crypto strong pseudo-random generator * this function may very well serve your needs. */ define sshufrand(seed) { local shuf_pow; /* power of two - log2(shuf_size) */ local shuf_seed; /* seed bits beyond low 64 bits */ local oldseed; /* previous seed */ local shift; /* shift factor to access 64 bit chunks */ local swap_indx; /* what to swap shuf_tbl[0] with */ local rval; /* random value form additive 55 generator */ local j; /* firewall */ if (!isint(seed)) { quit "bad arg: seed must be an integer"; } if (seed < 0) { quit "bad arg: seed < 0 is reserved for future use"; } /* * seed the additive 55 generator */ oldseed = sa55rand(seed); /* * form the shuffle table size and constants */ shuf_seed = seed >> 64; for (shuf_pow = 7; shuf_seed > (j=fact(1<<(shuf_pow))) && shuf_pow < 64; \ ++shuf_pow) { } shuf_size = (1 << shuf_pow); shuf_shift = 64 - shuf_pow; /* reallocate the shuffle table */ mat shuf_tbl[shuf_size]; /* * scramble the seed above the low 64 bits */ if (shuf_seed > 0) { j = 0; for (shift=0; shift < highbit(shuf_seed)+1; shift += 64) { j |= (randreseed64(shuf_seed >> shift) << shift); } shuf_seed = j; } /* * load the shuffle table */ for (j=0; j < shuf_size; ++j) { shuf_tbl[j] = a55rand(); } shuf_y = a55rand(); /* get the next Y value */ /* * We will shuffle based the process outlined in: * * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.4.2, page 139, Algorithm P. * * Here, we will let j run over the range [0,shuf_size) instead of * [shuf_size,0) as outlined in algorithm P. We will also generate * U values from shuf_seed. */ j = 0; while (shuf_seed > 0 && ++j < shuf_size) { /* determine what index we will swap with the '0' index */ quomod(shuf_seed, (j+1), shuf_seed, swap_indx); /* swap table entries, if needed */ if (swap_indx != j) { swap(shuf_tbl[j], shuf_tbl[swap_indx]); } } /* * run the generator for twice the table size */ for (j=0; j < shuf_size*2; ++j) { rval = shufrand(); } /* return the old seed */ return (oldseed); } /* * rand - generate a pseudo-random value over a given range via additive 55 * * usage: * rand() - generate a pseudo-random integer >=0 and < 2^64 * rand(a) - generate a pseudo-random integer >=0 and < a * rand(a,b) - generate a pseudo-random integer >=a and <= b * * returns: * a large pseudo-random integer over a give range (see usage) * * When no arguments are given, a pseudo-random number in the half open * interval [0,2^64) is produced. This form is identical to calling * shufrand(). * * When 1 argument is given, a pseudo-random number in the half open interval * [0,a) is produced. * * When 2 arguments are given, a pseudo-random number in the closed interval * [a,b] is produced. * * The input values a and b, if given, must be integers. * * This generator is simply a different interface to the shuffle generator. * calling shufrand(), or seeding via sshufrand() will affect the output * of this function. * * NOTE: Unlike cryrand(), this function does not preserve unused bits for * use by the next function call. * * NOTE: The Un*x rand() function returns only 16 bit or 31 bits, while we * return a number of any given size (default is 64 bits). * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you do not need a crypto strong pseudo-random generator * this function may very well serve your needs. */ define rand(a,b) { local range; /* we must generate [0,range) first */ local offset; /* what to add to get a adjusted range */ local ret; /* pseudo-random value */ local fullwords; /* number of full 64 bit chunks in ret */ local finalmask; /* mask of bits in final chunk of range */ local j; /* * setup and special cases */ /* deal with the rand() case */ if (isnull(a) && isnull(b)) { /* no args means same range as additive 55 generator */ return(a55rand()); } /* firewall - args, if given must be in integers */ if (!isint(a) || (!isnull(b) && !isint(b))) { quit "bad args: args, if given, must be integers"; } /* convert rand(x) into rand(0,x-1) */ if (isnull(b)) { /* convert call into a closed interval */ b = a-1; a = 0; /* firewall - rand(0) should act like rand(0,0) */ if (b == -1) { return(0); } } /* determine the range and offset */ if (a >= b) { /* deal with the case of rand(a,a) */ if (a == b) { /* not very random, but it is true! */ return(a); } range = a-b+1; offset = b; } else { /* convert rand(a,b), where a < b into rand(b,a) */ range = b-a+1; offset = a; } /* * At this point, we seek a pseudo-random number [0,range) to which * we will add offset to produce a number [offset,range+offset). */ fullwords = highbit(range-1)//64; finalmask = (1 << (1+(highbit(range-1)%64)))-1; /* * loop until we get a value that is in range * * A note in modulus biasing: * * We will not fall into the trap of thinking that we can simply take * a value mod 'range'. Consider the case where 'range' is '80' * and we are given pseudo-random numbers [0,100). If we took them * mod 80, then the numbers [0,20) would be produced more frequently * because the numbers [81,100) mod 80 wrap back into [0,20). */ do { /* load up all lower full 64 bit chunks with pseudo-random bits */ ret = 0; for (j=0; j < fullwords; ++j) { ret = (ret << 64) + shufrand(); } /* load the highest chunk */ ret <<= (highbit(finalmask)+1); ret |= (shufrand() >> (64-highbit(finalmask)-1)); } while (ret >= range); /* * return the adjusted range value */ return(ret+offset); } /* * srand - seed the pseudo-random additive 55 generator * * input: * seed * * returns: * old_seed * * This function actually seeds the shuffle generator (and indirectly * the additive 55 generator used by rand() and a55rand(). * * See sshufrand() and sa55rand() for information about a seed. * * There is no limit on the size of a seed. On the other hand, * extremely large seeds require large tables and long seed times. * Using a seed in the range of [2^64, 2^64 * 128!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 215 digits long, or * 64 to 780 bits long. * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. * * NOTE: If you do not need a crypto strong pseudo-random generator * this function may very well serve your needs. */ define srand(seed) { if (!isint(seed)) { quit "bad arg: seed must be an integer"; } if (seed < 0) { quit "bad arg: seed < 0 is reserved for future use"; } return(sshufrand(seed)); } /* * cryrand - cryptographically strong pseudo-random number generator * * usage: * cryrand(len) * * given: * len number of pseudo-random bits to generate * * returns: * a cryptographically strong pseudo-random number of len bits * * Internally, bits are produced log2(log2(n=p*q)) at a time. If a * call to this function does not exhaust all of the collected bits, * the unused bits will be saved away and used at a later call. * Setting the seed via scryrand() or srandom() will clear out all * unused bits. Thus: * * scryrand(0); <-- restore generator to initial state * cryrand(16); <-- 16 bits * * will produce the same value as: * * scryrand(0); <-- restore generator to initial state * cryrand(4)<<12 | cryrand(12); <-- 4+12 = 16 bits * * and will produce the same value as: * * scryrand(0); <-- restore generator to initial state * cryrand(3)<<13 | cryrand(7)<<6 | cryrand(6); <-- 3+7+6 = 16 bits * * The crypto generator is not as fast as most generators, though it is not * painfully slow either. * * NOTE: This function is the Blum cryptographically strong * pseudo-random number generator! */ define cryrand(len) { local goodbits; /* the number of good bits generated each pass */ local goodmask; /* mask for the low order good bits */ local randval; /* pseudo-random value being generated */ /* * firewall */ if (!isint(len) || len < 1) { quit "bad arg: len must be an integer > 0"; } /* * Determine how many bits may be generated each pass. * * The result by Alexi et. al., says that the log2(log2(n=p*q)) * least significant bits are secure, where log2(x) is log base 2. */ goodbits = highbit(highbit(cryrand_n)); goodmask = (1 << goodbits)-1; /* * If we have bits left over from the previous call, collect * them now. */ if (cryrand_bitcnt > 0) { /* case where the left over bits are enough for this call */ if (len <= cryrand_bitcnt) { /* we need only len bits */ randval = (cryrand_left >> (cryrand_bitcnt-len)); /* save the unused bits for later use */ cryrand_left &= ((1 << (cryrand_bitcnt-len))-1); /* save away the number of bits that we will not use */ cryrand_bitcnt -= len; /* return our complete result */ return(randval); /* case where we need more than just the left over bits */ } else { /* clear out the number of left over bits */ len -= cryrand_bitcnt; cryrand_bitcnt = 0; /* collect all of the left over bits for now */ randval = cryrand_left; } /* case where we have no previously left over bits */ } else { randval = 0; } /* * Pump out len cryptographically strong pseudo-random bits, * 'goodbits' at a time using Blum's process. */ while (len >= goodbits) { /* generate the bits */ cryrand_exp = (cryrand_exp^2) % cryrand_n; randval <<= goodbits; randval |= (cryrand_exp & goodmask); /* reduce the need count */ len -= goodbits; } /* if needed, save the unused bits for later use */ if (len > 0) { /* generate the bits */ cryrand_exp = (cryrand_exp^2) % cryrand_n; randval <<= len; randval |= ((cryrand_exp&goodmask) >> (goodbits-len)); /* save away the number of bits that we will not use */ cryrand_left = cryrand_exp & ((1 << (goodbits-len))-1); cryrand_bitcnt = goodbits-len; } /* * return our pseudo-random bits */ return(randval); } /* * scryrand - seed the cryptographically strong pseudo-random number generator * * usage: * scryrand(seed) * scryrand() * scryrand(seed,len1,len2) * scryrand(seed,ip,iq,ir) * * input: * [seed pseudo-random seed * [len1 len2] minimum bit length of the Blum primes 'p' and 'q' * -1 => default lengths * [ip iq ir] Initial search values for Blum primes 'p', 'q' and * a quadratic residue 'r' * * returns: * the previous seed * * * This function will seed and setup the generator needed to produce * cryptographically strong pseudo-random numbers. See the function * a55rand() and sshufrand() for information about how 'seed' works. * * The first form of this function are fairly fast if the seed is not * excessively large. The second form is also fairly fast if the internal * primes are not too large. The third form, can take a long time to call. * (see below) The fourth form, if the 'seed' arg is not -1, can take * as long as the third form to call. If the fourth form is called with * a 'seed' arg of -1, then it is fairly fast. * * Calling scryrand() with 1 or 3 args (first and third forms), or * calling srandom(), or calling scryrand() with 4 args with the first * arg >0, will leave the shuffle generator in a seeded state as if * sshufrand(seed) has been called. * * Calling scryrand() with no args will not seed the shuffle generator, * before or afterwards, however the shuffle generator will have been * changed as a side effect of that call. * * Calling scryrand() with 4 args where the first arg is 0 or '-1' * will not change the other generators. * * * First form of call: scryrand(seed) * * The first form of this function will seed the shuffle generator * (via srand). The default precomputed constants will be used. * * * Second form of call: scryrand() * * Only a new quadratic residue of n=p*q is recomputed. The previous prime * values are kept. * * Unlike the first and second forms of this function, the shuffle * generator function is not seeded before or after the call. The * current state is used to generate a new quadratic residue of n=p*q. * * * Third form of call: scryrand(seed,len1,len2) * * In the third form, 'len1' and 'len2' guide this function in selecting * internally used prime numbers. The larger the lengths, the longer * the time this function will take. The impact on execution time of * cryrand() and random() may also be noticed, but not as much. * * If a length is '-1', then the default lengths (248 for len1, and 264 * for len2) are used. The call scryrand(0,-1,-1) recreates the initial * crypto state the slow and hard way. (use scryrand(0) or srandom(0)) * * This function can take a long time to call given reasonable values * of len1 and len2. On a Pyramid R3000, the time to seed was: * * Approx value digits seed time * of len1+len2 in n=p*q in sec * ------------ -------- ------ * 8 3 0.53 * 16 5 0.54 * 32 10 0.79 * 64 20 1.17 * 128 39 2.89 * 200 61 4.68 * 256 78 7.49 * 322 100 12.47 * 464 140 35.56 * 512 155 53.57 * 664 200 83.97 * 830 250 122.93 * 996 300 242.49 * 1024 309 295.66 * 1328 400 663.44 * 1586 478 2002.10 * 1660 500 1643.45 (Faster mult/square methods kick in * 1992 600 2885.81 in certain cases. Type help config * 2048 617 1578.06 in calc for more details.) * * NOTE: The small lengths above are given for comparison * purposes and are NOT recommended for actual use. * * NOTE: Generating crypto pseudo-random numbers is MUCH * faster than seeding a crypto generator. * * NOTE: This calc lib file is intended for demonstration * purposes. Writing a C program (with possible assembly * or libmp assist) would produce a faster generator. * * * Fourth form of call: scryrand(seed,ip,iq,ir) * * In the fourth form, 'ip', 'iq' and 'ir' serve as initial search * values for the two Blum primes 'p' and 'q' and an associated * quadratic residue 'r' respectively. Unlike the 3rd form, where * lengths are given, the fourth form allows one to specify minimum * search values. * * The 'seed' value is interpreted as follows: * * If seed > 0: * * Seed and use the shuffle generator to generate 3 jump values * that are in the range '[0,ip)', '[0,iq)' and '[0,ir)' respectively. * Start searching for legal 'p', 'q' and 'r' values by adding * the jump values to their respective argument values. * * If seed == 0: * * Start searching for legal 'p', 'q' and 'r' values from * 'ip', 'iq' and 'ir' respectively. * * This form does not change/seed the other generators. * * If seed == -1: * * Let 'p' == 'ip', 'q' == 'iq' and 'r' == 'ir'. Do not check * if the value given are legal Blum primes or an associated * quadratic residue respectively. * * This form does not change/seed the other generators. * * WARNING: No checks are performed on the args passed. * Passing improper values will likely produce * poor results, or worse! * * * It should be noted that calling scryrand() while using the default * primes took only 0.04 seconds. Calling scryrand(0,-1,-1) took * 47.19 seconds. * * The paranoid, when giving explicit lengths, should keep in mind that * len1 and len2 are the largest powers of 2 that are less than the two * probable primes ('p' and 'q'). These two primes will be used * internally to cryrand(). For simplicity, we refer to len1 and len2 * as bit lengths, even though they are actually 1 less then the * minimum possible prime length. * * The actual lengths may exceed the lengths by slightly more than 3%. * Furthermore, part of the strength of this generator rests on the * difficultly to factor 'p*q'. Thus one should select 'len1' and 'len2' * (from which 'p' and 'q' are selected) such that factoring a 'len1+len2' * bit number is difficult. * * Not being able to factor 'n=p*q' into 'p' and 'q' does not directly * improve the crypto generator. On the other hand, it can't hurt. * * There is no limit on the size of a seed. On the other hand, * extremely large seeds require large tables and long seed times. * Using a seed in the range of [2^64, 2^64 * 128!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 215 digits long, or * 64 to 780 bits long. * * NOTE: This function will clear any internally buffer bits. See * cryrand() for details. * * NOTE: This function seeds the Blum cryptographically strong * pseudo-random number generator. */ define scryrand(seed,len1,len2,arg4) { local rval; /* a temporary pseudo-random value */ local oldseed; /* the previous seed */ local newres; /* the new quad res */ local ip; /* initial Blum prime 'p' search value */ local iq; /* initial Blum prime 'q' search value */ local ir; /* initial quadratic residue search value */ local rlim; /* high quadratic res search value */ /* * firewall - avoid bogus args and very trivial lengths */ /* catch the case of no args - compute a different quadratic residue */ if (isnull(seed) && isnull(len1) && isnull(len2)) { /* generate the next quadratic residue */ do { newres = cryres(cryrand_p, cryrand_q); } while (newres == cryrand_r); cryrand_r = newres; cryrand_exp = cryrand_r; /* clear the internal bits */ cryrand_left = 0; cryrand_bitcnt = 0; /* return the current seed early */ return (cry_seed); } if (!isint(seed)) { quit "bad arg: seed arg (1st) must be an integer"; } if (param(0) == 4) { if (seed < -1) { quit "bad arg: with 4 args: a seed < -1 is reserved for future use"; } } else { if (4 && seed < 0) { quit "bad arg: a seed arg (1st) < 0 is reserved for future use"; } } /* * 4 arg case: select or search for 'p', 'q' and 'r' from given values */ if (param(0) == 4) { /* set initial values */ ip = len1; iq = len2; ir = arg4; /* * Unless prohibited by a seed if -1, force minimum values on * 'ip', 'iq' and 'ir'. */ if (seed >= 0) { if (!isint(ip) || ip < 3) { /* smallest Blum prime */ ip = 3; } if (!isint(iq) || iq < 3) { /* smallest Blum prime */ iq = 3; } if (!isint(ir) || ir < 4) { /* cryres() never selects a value < 4 */ ir = 4; } } /* * Determine our prime search points */ if (seed > 0) { /* add in a random value */ oldseed = srand(seed); ip += rand(ip); iq += rand(iq); } /* * force ip <= iq */ if (ip > iq) { swap(ip, iq); } /* * find the first Blum prime 'p' */ if (seed >= 0) { cryrand_p = nxtprime(ip,3,4); } else { /* seed == -1: assume 'ip' is a Blum prime */ cryrand_p = ip; } /* * find the 2nd Blum prime 'q' > 'p', if needed */ if (seed >= 0) { if (iq <= cryrand_p) { iq = cryrand_p + 2; } cryrand_q = nxtprime(iq,3,4); } else { /* seed == -1: assume 'iq' is a Blum prime */ cryrand_q = iq; } /* remember our p*q Blum prime product as well */ cryrand_n = cryrand_p*cryrand_q; /* * search for a quadratic residue */ if (seed >= 0) { /* add in a random value to 'ir' if seeded */ if (seed > 0) { ir += rand(ir); } /* * increment until we find a quadratic value * * p is prime and J(r,p) == 1 ==> r is a quadratic residue of p * q is prime and J(q,p) == 1 ==> r is a quadratic residue of q * * J(r,p)*J(r,q) == J(r,p*q) * J(r,p) and J(q,p) == 1 ==> J(r,p*q) == 1 * J(r,p*q) == 1 ==> r is a quadratic residue of p*q * * Try to avoid trivial quadratic residues by forcing the search * over the interval [4, n-3). */ rlim = cryrand_n-3; /* if ir is too big, drop down to the bottom of the range */ if (ir >= rlim) { ir = 4; } while (jacobi(ir,cryrand_p) != 1 || jacobi(ir,cryrand_q) != 1) { /* if ir is too big, drop down to the bottom of the range */ if (++ir >= rlim) { ir = 4; } } } cryrand_r = ir; /* * clear the previously unused cryrand bits & other misc setup */ cryrand_left = 0; cryrand_bitcnt = 0; cryrand_exp = cryrand_r; /* * reseed the generator, if needed * * The crypto generator no longer needs the additive 55 and shuffle * generators. We however, restore the additive 55 and shuffle * generators back to its seeded state in order to be sure that it * will be left in the same state. * * This will make more reproducible, calls to the additive 55 and * shuffle generator; or more reproducible, calls to this function * without args. */ if (seed > 0) { ir = srand(seed); /* ignore this return value */ return(oldseed); } else { /* no seed change, return the current seed */ return (cry_seed); } } /* * If not the 4 arg case: * * convert explicit -1 args into default values * convert missing args into -1 values (use precomputed tables) */ if ((isint(len1) && len1 != -1 && len1 < 4) || (isint(len2) && len2 != -1 && len2 < 4) || (!isint(len1) && isint(len2)) || (isint(len1) && !isint(len2))) { quit "bad args: 2 & 3: if 2nd is given, must be -1 or ints > 3"; } if (isint(len1) && len1 == -1) { len1 = 248; /* default len1 value */ } if (isint(len2) && len2 == -1) { len2 = 264; /* default len2 value */ } if (!isint(len1) && !isint(len2)) { /* from here down, -1 means use precomputed values */ len1 = -1; len2 = -1; } /* * force len1 <= len2 */ if (len1 > len2) { swap(len1, len2); } /* * seed the generator */ oldseed = srand(seed); /* * generate p and q Blum primes * * The Blum process requires the primes to be of the form 3 mod 4. * We also generate n=p*q for future reference. * * We make sure that the lengths are the minimum lengths possible. * We want some range to select a random prime from, so we * go at least 3 bits higher, and as much as 3% plus 3 bits * higher. Since the section is a random, how high really * does not matter that much, but we want to avoid going to * an extreme to keep the execution time from getting too long. * * Finally, we generate a quadratic residue of n=p*q. */ if (len1 > 0) { /* generate a pseudo-random prime ~len1 bits long */ rval = rand(2^(len1-1), 2^((int(len1*1.03))+3)); cryrand_p = nxtprime(rval,3,4); } else { /* use precomputed 'p' value */ cryrand_p = cryrand_init_p; } if (len2 > 0) { /* generate a pseudo-random prime ~len1 bits long */ rval = rand(2^(len2-1), 2^((int(len2*1.03))+3)); cryrand_q = nxtprime(rval,3,4); } else { /* use precomputed 'q' value */ cryrand_q = cryrand_init_q; } /* * find the quadratic residue */ cryrand_n = cryrand_p*cryrand_q; cryrand_r = cryres(cryrand_p, cryrand_q); /* * clear the previously unused cryrand bits & other misc setup */ cryrand_left = 0; cryrand_bitcnt = 0; cryrand_exp = cryrand_r; /* * reseed the generator * * The crypto generator no longer needs the additive 55 and shuffle * generators. We however, restore the additive 55 and shuffle * generators back to its seeded state in order to be sure that it * will be left in the same state. * * This will make more reproducible, calls to the additive 55 and * shuffle generator; or more reproducible, calls to this function * without args. */ /* we do not care about this old seed */ rval = srand(seed); /* * return the old seed */ return(oldseed); } /* * random - a cryptographically strong pseudo-random number generator * * usage: * random() - generate a pseudo-random integer >=0 and < 2^64 * random(a) - generate a pseudo-random integer >=0 and < a * random(a,b) - generate a pseudo-random integer >=a and <= b * * returns: * a large cryptographically strong pseudo-random number (see usage) * * This function is just another interface to the crypto generator. * (see the cryrand() function). * * When no arguments are given, a pseudo-random number in the half open * interval [0,2^64) is produced. This form is identical to calling * cryrand(64). * * When 1 argument is given, a pseudo-random number in the half open interval * [0,a) is produced. * * When 2 arguments are given, a pseudo-random number in the closed interval * [a,b] is produced. * * This generator uses the crypto to return a large pseudo-random number. * * The input values a and b, if given, must be integers. * * Internally, bits are produced log2(log2(n=p*q)) at a time. If a * call to this function does not exhaust all of the collected bits, * the unused bits will be saved away and used at a later call. * Setting the seed via scryrand(), srandom() or cryrand(len,1) * will clear out all unused bits. * * NOTE: The BSD random() function returns only 31 bits, while we return 64. * * NOTE: This function is the Blum cryptographically strong * pseudo-random number generator! */ define random(a,b) { local range; /* we must generate [0,range) first */ local offset; /* what to add to get a adjusted range */ local rangebits; /* the number of bits in range */ local ret; /* pseudo-random bit value */ /* * setup and special cases */ /* deal with the rand() case */ if (isnull(a) && isnull(b)) { /* no args means return 64 bits */ return(cryrand(64)); } /* firewall - args, if given must be in integers */ if (!isint(a) || (!isnull(b) && !isint(b))) { quit "bad args: args, if given, must be integers"; } /* convert rand(x) into rand(0,x-1) */ if (isnull(b)) { /* convert call into a closed interval */ b = a-1; a = 0; /* firewall - rand(0) should act like rand(0,0) */ if (b == -1) { return(0); } } /* determine the range and offset */ if (a >= b) { /* deal with the case of rand(a,a) */ if (a == b) { /* not very random, but it is true! */ return(a); } range = a-b+1; offset = b; } else { /* convert random(a,b), where a<b, into random(b,a) */ range = b-a+1; offset = a; } rangebits = highbit(range-1)+1; /* * At this point, we seek a pseudo-random number [0,range) to which * we will add offset to produce a number [offset,range+offset). */ /* * loop until we get a value that is in range * * We will obtain pseudo-random values over the range [0,2^rangebits) * where 2^rangebits >= range and 2^(rangebits-1) < range. We * will ignore any results that are > the range that we want. * * A note in modulus biasing: * * We will not fall into the trap of thinking that we can simply take * a value mod 'range'. Consider the case where 'range' is '80' * and we are given pseudo-random numbers [0,100). If we took them * mod 80, then the numbers [0,20) would be produced more often * because the numbers [81,100) mod 80 wrap back into [0,20). */ do { /* obtain a pseudo-random value */ ret = cryrand(rangebits); } while (ret >= range); /* * return the adjusted range value */ return(ret+offset); } /* * srandom - seed the cryptographically strong pseudo-random number generator * * given: * seed a random number seed * * returns: * the previous seed * * This function is just another interface to the crypto generator. * (see the scryrand() function). * * This function makes indirect use of the additive 55 and shuffle * generator. * * There is no limit on the size of a seed. On the other hand, * extremely large seeds require large tables and long seed times. * Using a seed in the range of [2^64, 2^64 * 128!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 215 digits long, or * 64 to 780 bits long. * * NOTE: Calling this function will clear any internally buffer bits. * See cryrand() for details. * * NOTE: This function seeds the Blum cryptographically strong * pseudo-random number generator! */ define srandom(seed) { if (!isint(seed)) { quit "bad arg: seed must be an integer"; } if (seed < 0) { quit "bad arg: seed < 0 is reserved for future use"; } return(scryrand(seed)); } /* * randstate - set/get the state of all of the generators * * usage: * randstate() return the current state * randstate(0) return the previous state, set the default state * randstate(cobj) return the previous state, set a new state * * In the first form: randstate() * * This function returns an cryobj object containing information * about the current state of all of the generators. * * In the second form: randstate(0) * * This function sets all of the generators to the default initial * state (i.e., the state when this library was loaded). * * This function returns an cryobj object containing information * about the previous state of all of the generators. * * In the third form: randstate(cobj) * * This function sets all of the generators to the state as found * in the cryobj object. * * This function returns an cryobj object containing information * about the previous state of all of the generators. * * This function may be used to save and restore cryrand() & random() * generator states. For example: * * state = randstate() <-- save the current state * random() <-- print the next 64 bits * randstate(state) <-- restore previous state * random() <-- print the same 64 bits * * One may quickly reseed a generator. For example: * * srandom(1,330,350) <-- seed the generator * seed1state = randstate() <-- remember this 1st seeded state * random() <-- print 1st 64 bits seed 1 generator * srandom(2,331,351) <-- seed the generator again * seed2state = randstate() <-- remember this 2nd seeded state * random() <-- print 1st 64 bits seed 2 generator * * randstate(seed1state) <-- reseed to the 1st seeded state * random() <-- reprint 1st 64 bits seed 1 generator * randstate(seed2state) <-- reseed to the 2nd seeded state * random() <-- reprint 1st 64 bits seed 2 generator * * oldstate = randstate(0) <-- seed to the default generator * random() <-- print 1st 64 bits from default * a55rand() <-- print 1st 64 bits a55 generator * prevstate = randstate(oldstate) <-- restore seed 2 generator * random() <-- print 2nd 64 bits seed 2 generator * randstate(prevstate) <-- restore def generator in progress * random() <-- print 2nd 64 bits default generator * a55rand() <-- print 2nd 64 bits a55 generator * * given: * cobj if a cryobj object, use that object to set the current state * if 0, set to the default state * * return: * return the state of the crypto pseudo-random number generator in * the form of an cryobj object, as it was prior to this call * * NOTE: No checking is performed on the data the 3rd form (cryobj object * arg) is used. The user must ensure that the arg represents a valid * generator state. * * NOTE: When using the second form (passing an integer arg), only 0 is * defined. All other integer values are reserved for future use. */ define randstate(arg) { local x; /* firewall comparator */ local prev; /* previous states of the generators */ local junk; /* dummy holder of random values */ /* declare our objects */ obj cryobj x; /* firewall comparator */ obj cryobj prev; /* previous states of the generators */ /* firewall */ if (!isint(arg) && !istype(arg,x) && !isnull(arg)) { quit "bad arg: argument must be integer, an cryobj object or missing"; } if (isint(arg) && arg != 0) { quit "bad arg: non-zero integer arguments are reserved for future use"; } /* * save the current state */ prev.p = cryrand_p; prev.q = cryrand_q; prev.r = cryrand_r; prev.exp = cryrand_exp; prev.left = cryrand_left; prev.bitcnt = cryrand_bitcnt; prev.a55j = add55_j; prev.a55k = add55_k; prev.seed = cry_seed; prev.shufy = shuf_y; prev.shufsz = shuf_size; prev.shuftbl = shuf_tbl; prev.a55tbl = add55_tbl; if (isnull(x)) { /* if no args, just return current state */ return (prev); } /* * deal with the cryobj arg - set the state */ if (istype(arg, x)) { /* set the state from this object */ cryrand_p = arg.p; cryrand_q = arg.q; cryrand_n = cryrand_p*cryrand_q; cryrand_r = arg.r; cryrand_exp = arg.exp; cryrand_left = arg.left; cryrand_bitcnt = arg.bitcnt; add55_j = arg.a55j; add55_k = arg.a55k; cry_seed = arg.seed; add55_seed64 = randreseed64(cry_seed); shuf_y = arg.shufy; shuf_size = arg.shufsz; shuf_shift = (64-highbit(shuf_size)); mat shuf_tbl[shuf_size]; shuf_tbl = arg.shuftbl; add55_tbl = arg.a55tbl; /* * deal with the 0 integer arg - set the default initial state */ } else if (isint(arg) && arg == 0) { cryrand_p = cryrand_init_p; cryrand_q = cryrand_init_q; cryrand_n = cryrand_p * cryrand_q; cryrand_r = cryrand_init_r; cryrand_exp = cryrand_r; cryrand_left = 0; cryrand_bitcnt = 0; cry_seed = 0; cry_seed = sshufrand(0); } /* * return the previous state */ return (prev); } /* * nxtprime - find a probable prime >= n_arg * * usage: * nxtprime(n_arg) * nxtprime(n_arg, modval, modulus) * * given: * n_arg lower bound of the search * [modval modulus] if given, look for numbers mod modulus == modval * * returns: * A number is that is very likely prime. * * In the first case 'nxtprime(n_arg)', this function returns a probable * prime >= n_arg. In the second case 'nxtprime(n_arg, v, u)', this * function returns a probable prime >= n_arg that is also == v mod u. * * This function will not skip over a prime, through there is a * extremely unlikely chance that it will return a composite. * The odds that a number returned by this function is not prime * are 1 in 4^50. The failure rate of this function is many orders * or magnitude lower than the failure rate due to a hardware error. * * NOTE: This function can take a long time, given a large value of n_arg. */ define nxtprime(n_arg, modval, modulus) { local modgcd; /* gcd(modulus,modval) */ local n; /* value >= n_arg that is being tested */ local j; /* * firewall */ if (!isint(n_arg)) { quit "bad args: 1st arg must be an integer"; } if (!isnull(modulus) && !isint(modval)) { quit "bad args: 3rd arg, if 2nd arg is given, must be an integer"; } if (!isnull(modulus) && (!isint(modulus) || modulus <= 0)) { quit "bad args: 3nd arg, if given, must be an integer > 0"; } /* * get values < 3 out of the way */ n = n_arg; if (n < 3) { /* get the even prime out of the way, if possible */ if (isnull(modulus) || modulus == 1 || (n%modulus == modval%modulus)) { /* * 2 is the greatest odd prime, because * 2 is the least even prime :-) */ return(2); } /* we have eliminated everything < 3 */ n = 3; } /* * convert nxtprime(n) to nxtprime(n,1,2) * convert nxtprime(n,x,1) to nxtprime(n,1,2) * convert nxtprime(n,a,b) to nxtprime(n,a mod b,b) */ if (isnull(modulus) || modulus < 2) { modulus = 2; modval = 1; } modval %= modulus; /* * catch cases where no more primes == 'modval' mod 'modulus' exist */ modgcd = gcd(modval,modulus); if (modgcd > 1) { /* if beyond the modgcd, then no primes can exist */ if (n > modgcd) { print "n_arg:",n_arg," modval:",modval," modulus:",modulus; quit "no such prime of that form exists"; } /* else n <= modgcd, then our only chance is if modgcd is prime */ /* reject if modgcd has an obvious prime factor */ if (modgcd > 10 && gcd(modgcd,nxtprime_pfact10) != 1) { print "n_arg:",n_arg," modval:",modval," modulus:",modulus; quit "no such prime of that form exists"; } if (modgcd > 100 && gcd(modgcd,nxtprime_pfact100) != 1) { print "n_arg:",n_arg," modval:",modval," modulus:",modulus; quit "no such prime of that form exists"; } if (modgcd > 1000 && gcd(modgcd,nxtprime_pfact1000) != 1) { print "n_arg:",n_arg," modval:",modval," modulus:",modulus; quit "no such prime of that form exists"; } /* do 50 probable prime tests, for a 1 in 4^50 false prime rate */ if (!ptest(modgcd,50)) { print "n_arg:",n_arg," modval:",modval," modulus:",modulus; quit "no such prime of that form exists"; } /* modgcd is the only prime >= n */ return(modgcd); } /* * bump n up to the next possible case * * n will be an odd number == 'modval' mod 'modulus' */ if (n%modulus != modval) { j = n - (n%modulus) + modval; if (j < n) { n = j+modulus; } else { n = j; } } if (n%2 == 0) { n += modulus; } /* look for a prime */ n = n-modulus; do { /* try the next integer */ n = n+modulus; /* reject if it has an obvious prime factor */ if (n > 10 && gcd(n,nxtprime_pfact10) != 1) { continue; } if (n > 100 && gcd(n,nxtprime_pfact100) != 1) { continue; } if (n > 1000 && gcd(n,nxtprime_pfact1000) != 1) { continue; } /* do 50 probable prime tests */ if (!ptest(n,50)) { continue; } /* n is very likely a prime number */ return(n); } while (1); } /* * cryobj - how to initialize a cryobj object * * given: * p first Blum prime (prime 3 mod 4) * q second Blum prime (prime 3 mod 4) * r quadratic residue of n=p*q * exp used in computing crypto good bits * left bits unused from the last cryrand() call * bitcnt left contains bitcnt crypto good bits * a55j 1st additive 55 table pointer * a55k 2nd additive 55 table pointer * seed last seed set by sa55rand() or 0 * shufy Y (previous a55rand() output for shuffle) * shufsz size of the shuffle table * shuftbl a matrix of shufsz entries * a55tbl additive 55 generator state table * * return: * an cryobj object * * NOTE: This function, by convention, returns an cryobj object. */ define cryobj(p,q,r,exp,left,bitcnt,a55j,a55k,seed,shufy,shufsz,shuftbl,a55tbl) { local x; /* the object being created */ /* declare our objects */ obj cryobj x; /* firewall */ if (!isint(p) || !isint(q) || !isint(r) || !isint(exp) || \ !isint(left) || !isint(bitcnt) || !isint(a55j) || \ !isint(a55k) || !isint(seed) || !isint(shufy) || !isint(shufsz)) { quit "bad args: first 11 args must be integers"; } if (!ismat(shuftbl) || matdim(shuftbl) != 1 || \ matmin(shuftbl,1) != 0 || matmax(shuftbl,1) != shuf_size-1) { quit "bad arg: 12th is not a mat[0:shuf_size-1]"; } if (!ismat(a55tbl) || matdim(a55tbl) != 1 || \ matmin(a55tbl,1) != 0 || matmax(a55tbl,1) != 54) { quit "bad arg: 13th is not a mat[0:54]"; } /* initialize object with default startup values */ x.p = p; x.q = q; x.r = r; x.exp = exp; x.left = left; x.bitcnt = bitcnt; x.a55j = a55j; x.a55k = a55k; x.seed = seed; x.shufy = shuf_y; x.shufsz = shuf_size; x.shuftbl = shuf_tbl; x.a55tbl = a55tbl; /* return the initialized object */ return (x); } /* * cryobj_print - print the value of a cryobj object * * usage: * a an cryobj object * * NOTE: This function is called automatically when an cryobj object * is displayed. */ define cryobj_print(a) { local x; /* firewall comparator */ /* declare our objects */ obj cryobj x; /* firewall comparator */ /* firewall */ if (!istype(a, x)) { quit "bad arg: arg is not an cryobj object"; } if (!ismat(a.shuftbl) || matdim(a.shuftbl) != 1 || \ matmin(a.shuftbl,1) != 0 || matmax(a.shuftbl,1) != a.shufsz-1) { quit "bad arg: 12th is not a mat[0:shuf_size-1]"; } if (!ismat(a.a55tbl) || matdim(a.a55tbl) != 1 || \ matmin(a.a55tbl,1) != 0 || matmax(a.a55tbl,1) != 54) { quit "bad arg: 13th is not a mat[0:54]"; } /* print the value */ print "cryobj(" : a.p : "," : a.q : "," : a.r : "," : a.exp : "," : \ a.left : "," : a.bitcnt : "," : a.a55j : "," : a.a55k : "," : \ a.seed : "," : a.shufy : "," : a.shufsz : \ ",[" : a.shuftbl[0] : "," : a.shuftbl[1] : "," : \ a.shuftbl[2] : ",...," : a.shuftbl[52] : "," : \ a.shuftbl[53] : "," : a.shuftbl[54] : "]" : \ ",[" : a.a55tbl[0] : "," : a.a55tbl[1] : "," : \ a.a55tbl[2] : ",...," : a.a55tbl[52] : "," : \ a.a55tbl[53] : "," : a.a55tbl[54] : "])" : ; } /* * cryres - find a pseudo-random quadratic residue for scryrand() and cryrand() * * given: * p first prime * q second prime * * returns: * a number that is a quadratic residue of n=p*q * * This function is returns the pseudo-random quadratic residue of * the product of two primes. Normally this function is called * only by the crypto generator. * * NOTE: No check is made to ensure that the values passed are primes. * * NOTE: This is NOT Blum's method. This is used by Blum's method to * generate some internal values. */ define cryres(p,q) { local rval; /* a temporary pseudo-random value */ local sqrpow; /* a power of 2 starting > n^(3/4) */ local quadres; /* 0 or a quadratic residue of n = p*q */ local n; /* n=p*q */ local j; /* * firewall */ if (!isint(p) || !isint(q) || p < 3 || q < 3) { quit "bad args: p and q must be integers > 2"; } /* * find a pseudo-random quadratic residue of n = p*q * * To find a pseudo-random quadratic residue, we will generate * pseudo-random numbers to try in the interval [2^sqrpow,n-3), * where 2^sqrpow is the first power of 2 > n^(3/4). This range * helps us avoid selecting trivial residues abs(quadres mod n=p*q) * is tiny. We will never select a residue < 4. * * When we fail to find a quadratic residue after 1009 tries, we will * drop sqrpow by 1 and start at another pseudo-random location. * * It is very unlikely that we will need to search more than a * few numbers to find a quadratic residue of n = p*q. * * We will reject any quadratic residue that is a square of * itself, mod n=p*q. */ n = p*q; quadres = 0; sqrpow = highbit(n)//4*3; do { /* generate a pseudo-random starting point */ rval = rand(2^sqrpow, n-4); /* look for 1009 times or until >= cryrand_n */ for (j=0; j < 1009; ++j, ++rval) { /* * check if we have a quadratic residue of n = p*q * * p is prime and J(r,p) == 1 ==> r is a quadratic residue of p * q is prime and J(q,p) == 1 ==> r is a quadratic residue of q * * J(r,p)*J(r,q) == J(r,p*q) * J(r,p) and J(q,p) == 1 ==> J(r,p*q) == 1 * J(r,p*q) == 1 ==> r is a quadratic residue of p*q */ if (jacobi(rval,p) == 1 && jacobi(rval,q) == 1) { quadres = rval; break; } } /* setup for a new pseudo-random starting point if we found nothing */ if (quadres == 0) { /* reduce sqrpow if reasonable */ if (sqrpow > 2) { --sqrpow; } } } while (quadres == 0 || ((quadres^2)%n) == quadres); /* * return the quadratic residue of n = p*q */ return (quadres); } /* * randreseed64 - scramble a 64 bit seed * * given: * a 64 bit seed * * returns: * a 64 scrambled seed, or 0 if seed was 0 * * It is 'nice' when a seed of "n" produces a 'significantly different' * sequence than a seed of "n+1". Generators, by convention, assign * special significance to the seed of '0'. It is an unfortunate that * people often pick small seed values, particularly when large seed * are of significance to the generators found in this file. * * If 'seed' is 0, then 0 is returned. If 'seed' is non-zero, we will * produce a different and unique new scrambled 'seed'. This scrambling * will effectively eliminate the human factors and perceptions that * are noted above. * * It should be noted that the purpose of this process to scramble a seed * ONLY. We do not care if these generators produce good random numbers. * We only want to help eliminate the human factors and perceptions * noted above. * * This function scrambles the low 64 bits of a seed, by mapping [0,2^64) * into [0,2^64). This map is one-to-one and onto. Mapping is performed * using a linear congruence generator of the form: * * X1 <-- (a*X0 + c) mod m * * The generator are based on the linear congruential generators found in * Knuth's "The Art of Computer Programming - Seminumerical Algorithms", * vol 2, 2nd edition (1981), Section 3.6, pages 170-171. * * Because we process 64 bits we will take: * * m = 2^64 (based on note ii) * * We will scan the Rand book of numbers to look for an 'a' such that: * * a mod 8 == 5 (based on note iii) * 0.01*m < a < 0.99*m (based on note iv) * 0.01*2^64 < a < 0.99*2^64 * * To help keep the generators independent, we want: * * a is prime * * The choice of an adder 'c' is considered immaterial according (based * in note v). Knuth suggests 'c==1' or 'c==a'. We elect to select 'c' * using the same process as we used to select 'a'. The choice is * 'immaterial' after all, and as long as: * * gcd(c, m) == 1 (based on note v) * gcd(c, 2^64) == 1 * * the concerns are met. It can be shown that if we have: * * gcd(a, c) == 1 * * then the adders and multipliers will be more independent. * * We will obtain the values 'a' and 'c for our generator from the * Rand book of numbers. Because m=2^64 is 20 decimal digits long, we * will search the Rand book of numbers 20 at a time. We will skip any * of the 55 values that were used to initialize the additive 55 generators. * The values obtained from the Rand book are: * * a = 6316878969928993981 * c = 1363042948800878693 * * As we stated before, we must map 0 ==> 0. The linear congruence * generator would normally map as follows: * * 0 ==> 1363042948800878693 (0 ==> c) * * To determine which value maps back into 0, we compute: * * (-c*minv(a,m)) % m * * and thus we find that the congruence generator would also normally map: * * 10239951819489363767 ==> 0 * * To overcome this, and preserve the 1-to-1 and onto map, we force: * * 0 ==> 0 * 10239951819489363767 ==> 1363042948800878693 * * To repeat, this function converts a values into a seed value. With the * except of 'seed == 0', every value is mapped into a unique seed value. * This mapping need not be complex, random or secure. All we attempt * to do here is to allow humans who pick small or successive seed values * to obtain reasonably different sequences from the generators below. * * NOTE: This is NOT a random number generator. This function is intended * to be used internally by sa55rand() and sshufrand(). */ define randreseed64(seed) { local ret; /* return value */ local a; /* generator 0 multiplier */ local c; /* generator 0 adder */ /* firewall */ if (!isint(seed)) { quit "bad args: seed must be an integer"; } if (seed < 0) { quit "bad arg: seed < 0 is reserved for future use"; } /* if seed is 0, we will return 0 */ if (seed == 0) { return (0); } /* * process the low 64 bits of the seed */ a = 6316878969928993981; c = 1363042948800878693; ret = (((seed & cry_mask)*a + c) & cry_mask); /* * Normally, the above equation would map: * * f(0) == 1363042948800878693 * f(10239951819489363767) == 0 * * However, we have already forced f(0) == 0. To preserve the * 1-to-1 and onto map property, we force: * * f(10239951819489363767) ==> 1363042948800878693 */ if (ret == 0) { ret = c; } /* return the scrambled value */ return (ret); } /* * Initial read execution code */ cry_seed = srand(0); /* pre-initialize the tables */ global lib_debug; if (!isnum(lib_debug) || lib_debug>0) print "ver: 10.5 06:19:34 5/9/93"; if (!isnum(lib_debug) || lib_debug>0) print "shufrand() defined"; if (!isnum(lib_debug) || lib_debug>0) print "sshufrand(seed) defined"; if (!isnum(lib_debug) || lib_debug>0) print "rand([a, [b]]) defined"; if (!isnum(lib_debug) || lib_debug>0) print "srand(seed) defined"; if (!isnum(lib_debug) || lib_debug>0) print "cryrand([a, [b]]) defined"; if (!isnum(lib_debug) || lib_debug>0) print "scryrand([seed, [len1, len2]]) defined"; if (!isnum(lib_debug) || lib_debug>0) print "scryrand(seed, ip, iq, ir) defined"; if (!isnum(lib_debug) || lib_debug>0) print "random([a, [b]]) defined" if (!isnum(lib_debug) || lib_debug>0) print "srandom(seed) defined" if (!isnum(lib_debug) || lib_debug>0) print "obj cryobj defined"; if (!isnum(lib_debug) || lib_debug>0) print "randstate([cryobj | 0]) defined" if (!isnum(lib_debug) || lib_debug>0) print "nxtprime(n, [val, modulus]) defined";