/* * Copyright (c) 1996 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. * * Prior to calc 2.9.3t9, these routines existed as a calc library called * cryrand.cal. They have been rewritten in C for performance as well * as to make them available directly from libcalc.a. * * 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 * * chongo was here /\../\ */ /* * XXX - Add shs() and md5 hash functions. Ensure that any object can * be hashed. Ensure that if a == b, hash of a == hash of b. * This can be done by hashing all values of an value that * are used in the equality test. Note that the value type should * also be hashed to help distinguish different value types. * Also note that objects should hash their name. The shs() and * md5() should NOT replace the foohash() functions used by * associative arrays as those functions need to be fast. * * XXX - write random() and srandom() help pages */ /* * AN OVERVIEW OF THE FUNCTIONS: * * This module contains two pseudo-random number generators: * * Additive 55 shuffle generator: * * We refer to this generator as the a55 generator. * * rand - a55 shuffle generator * srand - seed the a55 shuffle generator * * This generator has two distinct parts, the a55 generator * and the shuffle generator. * * The additive 55 generator is 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. * * The shuffle generator is 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. If you need a fast generator and do not * need a cryptographically strong one, this generator is likely to do * the job. * * The shuffle generator is feed values by the additive 55 process. * * Blum-Blum-Shub generator: * * We refer to this generator as the Blum generator. * * 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. * * Blum, Blum, and Shub, "A Simple Unpredictable Pseudo-Random * Number Generator", SIAM Journal of Computing, v. 15, n. 2, * 1986, pp. 364-383. * * U. V. Vazirani and V. V. Vazirani, "Trapdoor Pseudo-Random * Number Generators with Applications to Protocol Design", * Proceedings of the 24th IEEE Symposium on the Foundations * of Computer Science, 1983, pp. 23-30. * * U. V. Vazirani and V. V. Vazirani, "Efficient and Secure * Pseudo-Random Number Generation", Proceedings of the 24th * IEEE Symposium on the Foundations of Computer Science, * 1984, pp. 458-463. * * U. V. Vazirani and V. V. Vazirani, "Efficient and Secure * Pseudo-Random Number Generation", Advances in Cryptology - * Proceedings of CRYPTO '84, Berlin: Springer-Verlag, 1985, * pp. 193-202. * * Sciences 28, pp. 270-299. * * Bruce Schneier, "Applied Cryptography", John Wiley & Sons, * 1st edition (1994), pp 365-366. * * This generator is considered 'strong' in that it passes all * polynomial-time statistical tests. The sequences produced * are random in an absolutely precise way. There is absolutely * no better way to predict the sequence than by tossing a coin * (as with TRULY random numbers) EVEN IF YOU KNOW THE MODULUS! * Furthermore, having a large chunk of output from the sequence * does not help. The BITS THAT FOLLOW OR PRECEDE A SEQUENCE * ARE UNPREDICTABLE! * * To compromise the generator, an adversary must either factor the * modulus or perform an exhaustive search just to determine the next * (or previous) bit. If we make the modulus hard to factor * (such as the product of two large well chosen primes) breaking * the sequence could be intractable for todays computers and methods. **** * * 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 need * * By using the appropriate seed and other arguments, one may * increase the strength of the generator to suit the need of * the application. One does not have just a few levels. * * Even though I have done my best to implement a good system, you still * must use these routines your own risk. * * Share and enjoy! :-) */ /* * 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. * The shuffle generator has a very good period, and is fast. It is * fairly good as generators go, particularly when it is feed reasonably * random numbers. Because of this, we use feed values from the additive * 55 process into the shuffle generator. * * The a55 generator uses 2 tables: * * additive table - 55 entries of 64 bits used by the additive 55 * part of the a55 generator * * shuffle table - 256 entries of 64 bits used by the shuffle * part of the a55 generator and feed by the * additive table. * * Casual direct use of the shuffle generator may be acceptable. If one * desires cryptographically strong random numbers, or if one is paranoid, * one should use the Blum generator instead. * * The a55 generator as the following calc interfaces: * * rand(min,max) (where min < max) * * Print an a55 generator random value over interval [a,b). * * rand() * * Same as rand(0, 2^64). Print 64 bits. * * rand(lim) (where 0 > lim) * * Same as rand(0, lim). * * randbit(x) (where x > 0) * * Same as rand(0, 2^x). Print x bits. * * randbit(skip) (where skip < 0) * * Skip random bits and return the bit skip count (-skip). * *** * * The Blum 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 Blum generator is not too slow, though * seeding the generator via srandom(seed,plen,qlen) can be slow. * Shortcuts and pre-defined generators have been provided for this reason. * Use of Blum should be more than acceptable for many applications. * * The Blum generator as the following calc interfaces: * * random(min, max) (where min < max) * XXX - write this function * * Print a Blum generator random value over interval [min,max). * * random() * XXX - write this function * * Same as random(0, 2^64). Print 64 bits. * * random(lim) (where 0 > lim) * XXX - write this function * * Same as random(0, lim). * * randombit(x) (where x > 0) * XXX - write this function * * Same as random(0, 2^x). Print x bits. * * randombit(skip) (where skip < 0) * XXX - write this function * * Skip skip random bits and return the bit skip count (-skip). */ /* * INITIALIZATION AND SEEDS: * * All generators come already seeded with precomputed initial constants. * Thus, it is not required to seed a generator before using it. * * The a55 generator may be initialized and seeded via srand(). * The Blum generator may be initialized and seeded via srandom(). * * Using a seed of '0' will reload generators with their initial states. * * srand(0) restore additive 55 generator to the initial state * srandom(0) restore Blum generator to the initial state * * The above single arg calls are fairly fast. * * The call: * * srandom(seed, newn) * * is fast when the config value "srandom" is 0, 1 or 2. * * Optimal seed range for the a55 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 * 55!) should be * sufficient for most purposes. An easy way to stay within this * range to to use seeds that are between 21 and 93 digits, or * 64 to 308 bits long. * * 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. * * Optimal seed range for the Blum generator: * * There is no limit on the size of a seed. On the other hand, * in most cases the seed is taken modulo the Blum modulus. * Using a seed that is too small (except for 0) results in * an internal generator be used to increase its size. * * It is faster to use seeds that are in the half open internal * [sqrt(n), n) where n is the Blum modulus. * * The default Blum modulus is 256 bits. The default * optimal size of a seed is between 128 and 256 bits. * * The exception is when srandom(seed, plen, qlen) is used. * When seed < 0, the seed is given to an internal a55 generator * and the a55 generator range (negated) applies. When seed > 0, * the seed is given to an internal Blum generator and the * 128 to 256 bit range applies. The value seed == 0 may also * be used in this type of call. * ***** * * srand(seed) * * Seed the a55 generator. * * seed != 0: * --------- * Any buffered random bits are flushed. The additive table is loaded * with the default additive table. The low order 64 bits of seed is * xor-ed against each table value. The additive table is shuffled * according to seed/2^64. * * The following calc code produces the same effect: * * (* reload default additive table xored with low 64 seed bits *) * seed_xor = seed & ((1<<64)-1); * for (i=0; i < 55; ++i) { * additive[i] = xor(default_additive[i], seed_xor); * } * * (* shuffle the additive table *) * seed >>= 64; * for (i=55; seed > 0 && i > 0; --i) { * quomod(seed, i+1, seed, j); * swap(additive[i], additive[j]); * } * * Seed must be >= 0. All seed values < 0 are reserved for future use. * * The additive 55 pointers are reset to additive[23] and additive[54]. * Last the shuffle table is loaded with successive values from the * additive 55 generator. * * seed == 0: * --------- * Restore the initial state and modulus of the a55 generator. * After this call, the a55 generator is restored to its initial * state after calc started. * * The additive 55 pointers are reset to additive[23] and additive[54]. * Last the shuffle table is loaded with successive values from the * additive 55 generator. * *** * * srand(mat55) * * Seed the a55 generator. * * Any buffered random bits are flushed. The additive table with the * first 55 entries of the array mat55, mod 2^64. * * The additive 55 pointers are reset to additive[23] and additive[54]. * Last the shuffle table is loaded with successive values from the * additive 55 generator. * *** * * srand() * * Return current a55 generator state. This call does not alter * the generator state. * *** * * srand(state) * * Restore the a55 state and return the previous state. Note that * the argument state is a rand state value (isrand(state) is true). * Any internally buffered random bits are restored. * * The states of the a55 generators can be saved by calling the seed * function with no arguments, and later restored by calling the seed * functions with that same return value. * * rand_state = srand(); * ... generate random bits ... * prev_rand_state = srand(rand_state); * ... generate the same random bits ... * srand() == prev_rand_state; (* is true *) * * Saving the state just after seeding a generator and restoring it later * as a very fast way to reseed a generator. * *** * * srandom(seed) * XXX - write this function * * Seed the Blum generator using the current Blum modulus. * * Here we assume that the Blum modulus is n. Any internally buffered * random bits are flushed. * * seed > 0: * -------- * Seed the an internal additive 55 shuffle generator, and use it * to produce an initial quadratic residue in the range: * * [2^(binsize*4/5), 2^(binsize-2)) * * where 2^(binsize-1) < n <= 2^binsize and 'n' is the current Blum * modulus. Here, binsize is the smallest power of 2 >= n. * * The follow calc script produces an equivalent effect: * * cur_state = srand(seed); * binsize = highbit(n)+1; (* n is the current Blum modulus *) * r = pmod(rand(1< 0, 1007 <= newn: * ---------------------- * If 'newn' passes the tests (if applicable) specified by the "srandom" * config value, it becomes the Blum modulus. Once the Blum modulus * is set, seed is used to seed an internal Additive 55 generator * state which in turn is used to set the initial quadratic residue. * * While not as efficient, this call is equivalent to: * * srandom(0, newn); * srandom(seed); * * seed < 0, 1007 <= newn: * ---------------------- * Reserved for future use. * * any seed, 20 < newn < 1007: * -------------------------- * Reserved for future use. * * seed == 0, 0 < newn <= 20: * ------------------------- * Seed with one of the predefined Blum moduli. * * The Blum moduli used by the pre-defined generators were generated * using the above process. The initial search values for the Blum * primes and the value used for selecting the initial quadratic * residue (by squaring it mod the Blum modulus) were produced by * special purpose hardware that produces cryptographically strong * random numbers. * * See the URL: * * http://lavarand.sgi.com * * for an explination of how the search points of the generators * were selected. * * XXX - This URL is not available on 16Jun96 ... but will be soon. * * The purpose of these pre-defined Blum moduli is to provide users with * an easy way to use a generator where the individual Blum primes used * are not well known. True, these values are in some way "MAGIC", on * the other hand that is their purpose! If this bothers you, don't * use them. See the section "FOR THE PARANOID" below for details. * * The value 'newn' determines which pre-defined generator is used. * For a given 'newn' the Blum modulus 'n' (product of 2 Blum primes) * and initial quadratic residue 'r' is set as follows: * * newn == 1: (Blum modulus bit length 130) * n = 0x5049440736fe328caf0db722d83de9361 * r = 0xb226980f11d952e74e5dbb01a4cc42ec * * newn == 2: (Blum modulus bit length 137) * n = 0x2c5348a2555dd374a18eb286ea9353443f1 * r = 0x40f3d643446cd710e3e893616b21e3a218 * * newn == 3: (Blum modulus bit length 147) * n = 0x9cfd959d6ce4e3a81f1e0f2ca661f11d001f1 * r = 0xfae5b44d9b64ff5cea4f3e142de2a0d7d76a * * newn == 4: (Blum modulus bit length 157) * n = 0x3070f9245c894ed75df12a1a2decc680dfcc0751 * r = 0x20c2d8131b2bdca2c0af8aa220ddba4b984570 * * newn == 5: (Blum modulus bit length 257) * n = 0x2109b1822db81a85b38f75aac680bc2fa5d3fe1118769a0108b99e5e799 * 166ef1 * r = 0x5e9b890eae33b792e821a9605f5df6db234f7b7d1e70aeed0e6c77c859e * 2efa9 * * newn == 6: (Blum modulus bit length 259) * n = 0xa7bfd9d7d9ada2c79f2dbf2185c6440263a38db775ee732dad85557f1e1 * ddf431 * r = 0x5e94a02f88667154e097aedece1c925ce1f3495d2c98eccfc5dc2e80c94 * 04daf * * newn == 7: (Blum modulus bit length 286) * n = 0x43d87de8f2399ef237801cd5628643fcff569d6b0dcf53ce52882e7f602 * f9125cf9ec751 * r = 0x13522d1ee014c7bfbe90767acced049d876aefcf18d4dd64f0b58c3992d * 2e5098d25e6 * * newn == 8: (Blum modulus bit length 294) * n = 0x5847126ca7eb4699b7f13c9ce7bdc91fed5bdbd2f99ad4a6c2b59cd9f0b * c42e66a26742f11 * r = 0x853016dca3269116b7e661fa3d344f9a28e9c9475597b4b8a35da929aae * 95f3a489dc674 * * newn == 9: (Blum modulus bit length 533) * n = 0x39e8be52322fd3218d923814e81b003d267bb0562157a3c1797b4f4a867 * 52a84d895c3e08eb61c36a6ff096061c6fd0fdece0d62b16b66b980f95112 * 745db4ab27e3d1 * r = 0xb458f8ad1e6bbab915bfc01508864b787343bc42a8aa82d9d2880107e3f * d8357c0bd02de3222796b2545e5ab7d81309a89baedaa5d9e8e59f959601e * f2b87d4ed20d * * newn == 10: (Blum modulus bit length 537) * n = 0x25f2435c9055666c23ef596882d7f98bd1448bf23b50e88250d3cc952c8 * 1b3ba524a02fd38582de74511c4008d4957302abe36c6092ce222ef9c73cc * 3cdc363b7e64b89 * r = 0x66bb7e47b20e0c18401468787e2b707ca81ec9250df8cfc24b5ffbaaf2c * f3008ed8b408d075d56f62c669fadc4f1751baf950d145f40ce23442aee59 * 4f5ad494cfc482 * * newn == 11: (Blum modulus bit length 542) * n = 0x497864de82bdb3094217d56b874ecd7769a791ea5ec5446757f3f9b6286 * e58704499daa2dd37a74925873cfa68f27533920ee1a9a729cf522014dab2 * 2e1a530c546ee069 * r = 0x8684881cb5e630264a4465ae3af8b69ce3163f806549a7732339eea2c54 * d5c590f47fbcedfa07c1ef5628134d918fee5333fed9c094d65461d88b13a * 0aded356e38b04 * * newn == 12: (Blum modulus bit length 549) * n = 0x3457582ab3c0ccb15f08b8911665b18ca92bb7c2a12b4a1a66ee4251da1 * 90b15934c94e315a1bf41e048c7c7ce812fdd25d653416557d3f09887efad * 2b7f66d151f14c7b99 * r = 0xdf719bd1f648ed935870babd55490137758ca3b20add520da4c5e8cdcbf * c4333a13f72a10b604eb7eeb07c573dd2c0208e736fe56ed081aa9488fbc4 * 5227dd68e207b4a0 * * newn == 13: (Blum modulus bit length 1048) * n = 0x1517c19166b7dd21b5af734ed03d833daf66d82959a553563f4345bd439 * 510a7bda8ee0cb6bf6a94286bfd66e49e25678c1ee99ceec891da8b18e843 * 7575113aaf83c638c07137fdd3a76c3a49322a11b5a1a84c32d99cbb2b056 * 671589917ed14cc7f1b5915f6495dd1892b4ed7417d79a63cc8aaa503a208 * e3420cca200323314fc49 * r = 0xd42e8e9a560d1263fa648b04f6a69b706d2bc4918c3317ddd162cb4be7a * 5e3bbdd1564a4aadae9fd9f00548f730d5a68dc146f05216fe509f0b8f404 * 902692de080bbeda0a11f445ff063935ce78a67445eae5c9cea5a8f6b9883 * faeda1bbe5f1ad3ef6409600e2f67b92ed007aba432b567cc26cf3e965e20 * 722407bfe46b7736f5 * * newn == 14: (Blum modulus bit length 1054) * n = 0x5e56a00e93c6f4e87479ac07b9d983d01f564618b314b4bfec7931eee85 * eb909179161e23e78d32110560b22956b22f3bc7e4a034b0586e463fd40c6 * f01a33e30ede912acb86a0c1e03483c45f289a271d14bd52792d0a076fdfe * fe32159054b217092237f0767434b3db112fee83005b33f925bacb3185cc4 * 409a1abdef8c0fc116af01 * r = 0xf7aa7cb67335096ef0c5d09b18f15415b9a564b609913f75f627fc6b0c5 * b686c86563fe86134c5a0ea19d243350dfc6b9936ba1512abafb81a0a6856 * c9ae7816bf2073c0fb58d8138352b261a704b3ce64d69dee6339010186b98 * 3677c84167d4973444194649ad6d71f8fa8f1f1c313edfbbbb6b1b220913c * c8ea47a4db680ff9f190 * * newn == 15: (Blum modulus bit length 1055) * n = 0x97dd840b9edfbcdb02c46c175ba81ca845352ebe470be6075326a26770c * ab84bfc0f2e82aa95aac14f40de42a0590445b902c2b8ebb916753e72ab86 * c3278cccc1a783b3e962d81b80df03e4380a8fa08b0d86ed0caa515c196a5 * 30e49c558ddb53082310b1d0c7aee6f92b619798624ffe6c337299bc51ff5 * d2c721061e7597c8d97079 * r = 0xb8220703b8c75869ab99f9b50025daa8d77ca6df8cef423ede521f55b1c * 25d74fbf6d6cc31f5ef45e3b29660ef43797f226860a4aa1023dbe522b1fe * 6224d01eb77dee9ad97e8970e4a9e28e7391a6a70557fa0e46eca78866241 * ba3c126fc0c5469f8a2f65c33db95d1749d3f0381f401b9201e6abd43d98d * b92e808f0aaa6c3e2110 * * newn == 16: (Blum modulus bit length 1062) * n = 0x456e348549b82fbb12b56f84c39f544cb89e43536ae8b2b497d426512c7 * f3c9cc2311e0503928284391959e379587bc173e6bc51ba51c856ba557fee * 8dd69cee4bd40845bd34691046534d967e40fe15b6d7cf61e30e283c05be9 * 93c44b6a2ea8ade0f5578bd3f618336d9731fed1f1c5996a5828d4ca857ac * 2dc9bd36184183f6d84346e1 * r = 0xb0d7dcb19fb27a07973e921a4a4b6dcd7895ae8fced828de8a81a3dbf25 * 24def719225404bfd4977a1508c4bac0f3bc356e9d83b9404b5bf86f6d19f * f75645dffc9c5cc153a41772670a5e1ae87a9521416e117a0c0d415fb15d2 * 454809bad45d6972f1ab367137e55ad0560d29ada9a2bcda8f4a70fbe04a1 * abe4a570605db87b4e8830 * * newn == 17: (Blum modulus bit length 2062) * n = 0x6177813aeac0ffa3040b33be3c0f96e0faf97ca54266bfedd7be68494f7 * 6a7a91144598bf28b3a5a9dc35a6c9f58d0e5fb19839814bc9d456bff7f29 * 953bdac7cafd66e2fc30531b8d544d2720b97025e22b1c71fa0b2eb9a499d * 49484615d07af7a3c23b568531e9b8507543362027ec5ebe0209b4647b7ff * 54be530e9ef50aa819c8ff11f6d7d0a00b25e88f2e6e9de4a7747022b949a * b2c2e1ab0876e2f1177105718c60196f6c3ac0bde26e6cd4e5b8a20e9f0f6 * 0974f0b3868ff772ab2ceaf77f328d7244c9ad30e11a2700a120a314aff74 * c7f14396e2a39cc14a9fa6922ca0fce40304166b249b574ffd9cbb927f766 * c9b150e970a8d1edc24ebf72b72051 * r = 0x53720b6eaf3bc3b8adf1dd665324c2d2fc5b2a62f32920c4e167537284d * a802fc106be4b0399caf97519486f31e0fa45a3a677c6cb265c5551ba4a51 * 68a7ce3c29731a4e9345eac052ee1b84b7b3a82f906a67aaf7b35949fd7fc * 2f9f4fbc8c18689694c8d30810fff31ebee99b1cf029a33bd736750e7fe0a * 56f7e1d2a9b5321b5117fe9a10e46bf43c896e4a33faebd584f7431e7edbe * bd1703ccee5771b44f0c149888af1a4264cb9cf2e0294ea7719ed6fda1b09 * fa6e016c039aeb6d02a03281bcea8c278dd2a807eacae6e52ade048f58f2e * b5193f4ffb9dd68467bc6f8e9d14286bfef09b0aec414c9dadfbf5c46d945 * d147b52aa1e0cbd625800522b41dac * * newn == 18: (Blum modulus bit length 2074) * n= 0x68f2a38fb61b42af07cb724fec0c7c65378efcbafb3514e268d7ee38e21 * a5680de03f4e63e1e52bde1218f689900be4e5407950539b9d28e9730e8e6 * ad6438008aa956b259cd965f3a9d02e1711e6b344b033de6425625b6346d2 * ca62e41605e8eae0a7e2f45c25119ef9eece4d3b18369e753419d94118d51 * 803842f4de5956b8349e6a0a330145aa4cd1a72afd4ef9db5d8233068e691 * 18ff4b93bcc67859f211886bb660033f8170640c6e3d61471c3b7dd62c595 * b156d77f317dc272d6b7e7f4fdc20ed82f172fe29776f3bddf697fb673c70 * defd6476198a408642ed62081447886a625812ac6576310f23036a7cd3c93 * 1c96f7df128ad4ed841351b18c8b78629 * r= 0x4735e921f1ac6c3f0d5cda84cd835d75358be8966b99ff5e5d36bdb4be1 * 2c5e1df70ac249c0540a99113a8962778dc75dac65af9f3ab4672b4c575c4 * 9926f7f3f306fd122ac033961d042c416c3aa43b13ef51b764d505bb1f369 * ac7340f8913ddd812e9e75e8fde8c98700e1d3353da18f255e7303db3bcbb * eda4bc5b8d472fbc9697f952cfc243c6f32f3f1bb4541e73ca03f5109df80 * 37219a06430e88a6e94be870f8d36dbcc381a1c449c357753a535aa5666db * 92af2aaf1f50a3ddde95024d9161548c263973665a909bd325441a3c18fc7 * 0502f2c9a1c944adda164e84a8f3f0230ff2aef8304b5af333077e04920db * a179158f6a2b3afb78df2ef9735ea3c63 * * newn == 19: (Blum modulus bit length 2133) * n= 0x230d7ab23bb9e8d6788b252ad6534bdde276540721c3152e410ad4244de * b0df28f4a6de063ba1e51d7cd1736c3d8410e2516b4eb903b8d9206b92026 * 64cacbd0425c516833770d118bd5011f3de57e8f607684088255bf7da7530 * 56bf373715ed9a7ab85f698b965593fe2b674225fa0a02ebd87402ffb3d97 * 172acadaa841664c361f7c11b2af47a472512ee815c970af831f95b737c34 * 2508e4c23f3148f3cdf622744c1dcfb69a43fd535e55eebcdc992ee62f2b5 * 2c94ac02e0921884fe275b3a528bdb14167b7dec3f3f390cd5a82d80c6c30 * 6624cc7a7814fb567cd4d687eede573358f43adfcf1e32f4ee7a2dc4af029 * 6435ade8099bf0001d4ae0c7d204df490239c12d6b659a79 * r= 0x8f1725f21e245e4fc17982196605b999518b4e21f65126fa6fa759332c8 * e27d80158b7537da39d001cc62b83bbef0713b1e82f8293dad522993f86d1 * 761015414b2900e74fa23f3eaaa55b31cffd2e801fefb0ac73fd99b5d0cf9 * a635c3f4c73d8892d36ad053fc17a423cdcbcf07967a8608c7735e287d784 * ae089b3ddea9f2d2bb5d43d2ee25be346832e8dd186fc7a88d82847c03d1c * 05ee52c1f2a51a85f733338547fdbab657cb64b43d44d41148eb32ea68c7e * 66a8d47806f460cd6573b6ca1dd3eeaf1ce8db9621f1e121d2bb4a1878621 * dd2dbdd7b5390ab06a5dcd9307d6662eb4248dff2ee263ef2ab778e77724a * 14c62406967daa0d9ad4445064483193d53a5b7698ef473 * * newn == 20: (Blum modulus bit length 2166) * n= 0x4fd2b820e0d8b13322e890dddc63a0267e5b3a648b03276066a3f356d79 * 660c67704c1be6803b8e7590ee8a962c8331a05778d010e9ba10804d661f3 * 354be1932f90babb741bd4302a07a92c42253fd4921864729fb0f0b1e0a42 * d66b6777893195abd2ee2141925624bf71ad7328360135c565064ee502773 * 6f42a78b988f47407ba4f7996892ffdc5cf9e7ab78ac95734dbf4e3a3def1 * 615b5b4341cfbf6c3d0a61b75f4974080bbac03ee9de55221302b40da0c50 * ded31d28a2f04921a532b3a486ae36e0bb5273e811d119adf90299a74e623 * 3ccce7069676db00a3e8ce255a82fd9748b26546b98c8f4430a8db2a4b230 * fa365c51e0985801abba4bbcf3727f7c8765cc914d262fcec3c1d081 * r= 0x46ef0184445feaa3099293ee960da14b0f8b046fa9f608241bc08ddeef1 * 7ee49194fd9bb2c302840e8da88c4e88df810ce387cc544209ec67656bd1d * a1e9920c7b1aad69448bb58455c9ae4e9cd926911b30d6b5843ff3d306d56 * 54a41dc20e2de4eb174ec5ac3e6e70849de5d5f9166961207e2d8b31014cf * 35f801de8372881ae1ba79e58942e5bef0a7e40f46387bf775c54b1d15a14 * 40e84beb39cd9e931f5638234ea730ed81d6fca1d7cea9e8ffb171f6ca228 * 56264a36a2a783fd7ac39361a6598ed3a565d58acf1f5759bd294e5f53131 * bc8e4ee3750794df727b29b1f5788ae14e6a1d1a5b26c2947ed46f49e8377 * 3292d7dd5650580faebf85fd126ac98d98f47cf895abdc7ba048bd1a * * NOTE: The Blum moduli associated with 1 <= newn < 12 are subject * to having their Blum moduli factored, depending in their size, * by small PCs in a reasonable to large supercomputers/highly * parallel processors over a long time. Their value lies in their * speed relative the the default Blum generator. As of Jan 1996, * the Blum moduli associated with 12 <= newn < 20 appear to * be well beyond the scope of hardware and algorithms. * See the section titled 'FOR THE PARANOID' for more details. * * seed > 0, 0 < newn <= 20: * ------------------------ * Use the same pre-defined Blum moduli 'n' noted above but use 'seed' * to find a different quadratic residue 'r'. * * While not as efficient, this call is equivalent to: * * srandom(0, newn); * srandom(seed); * * seed < 0, 0 < newn <= 20: * ------------------------ * Use the same pre-defined Blum moduli 'n' noted above but use '-seed' * to compute a different quadratic residue 'r'. * * This call has the same effect as: * * srandom(0, newn) * * followed by the setting of the quadratic residue 'r' as follows: * * r = pmod(seed, 2, n) * * where 'n' is the Blum moduli generated by 'srandom(0,newn)' and * 'r' is the new quadratic residue. * * NOTE: Because no checking on 'seed' is performed, it is recommended * that 'seed' be selected as follows: * * binsize = highbit(n)+1; * seed = -rand(1<= n=p*q. * * The use of the above range insures that the quadratic residue is * large, but not too large. We want to avoid residues that are * near 0 or that are near 'n'. Such residues are trivial or * semi-trivial. Applying the same restriction to the square * of the initial residue avoid initial residues near 'sqrt(n)'. * Such residues are trivial or semi-trivial as well. * * Lower bound 2^(binsize*4/5) (4/5 the size of the smallest power of 2 >= n) * is used because it avoids initial quadratic residues near 0, n^1/4, n^1/2, * n^1/3, n^2/3 and n^3/4. For a trivial example, take the trivial case of * selecting a quadratic residue of 1, 0 or n-1. Repeated squarings produce * poor results. Similar but far less drastic results come from an * initial selection that is near n^1/2 or other small fractional power. * While the above initial quadratic residue range range allows for * powers of n such as n^3/7, n^5/6, these powers are more complex and * produce less obvious patterns when squared mod n. * * The upper bound of 2^(binsize-2) allows one to avoid initial quadratic * residues near 'n'. Since n could be as small as 2^(binsize-1)+1, we * must use the next lower power of 2: 2^(binsize-2) to be sure that we * avoid initial quadratic residues near n. * * Taking some care to select a good initial residue helps eliminate cheap * search attacks. It is true that a subsequent residue could be one of the * residues that we would first avoid. However such an occurrence will * happen after the generator is well underway and any such seed information * has been lost. * * The size of Blum modulus 'n=p*q' was taken to be > 2^1024, or 1025 bits * (309 digits) long. As if Jan 1996, the upper reach of the state of * the art for factoring general numbers was around 2^512. We selected * 2^1024 because it was twice that size and would hopefully remain well * beyond the reach of Number Theory and CPU power for some time. * * Not being able to factor 'n=p*q' into 'p' and 'q' does not directly * improve the quality Blum generator. On the other hand, it does * improve the security of it. * * The number of bits produced each cycle for a given Blum modulus 'n' * is int(log2(log2(n))). Thus for 2^1024 <= n < 2^2048, 10 bits are * produced. For optimal performance, we use a Blum modulus that is * slightly larger than 2^(2^x) to produce 'x' bits at a time. * * The lengths of the two Blum probable primes 'p' and 'q' used to make up * the default Blum modulus 'n=p*q' differ slightly to avoid certain * 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 up to 6% of the product size to avoid such attacks. * Clearly one does not want the size of the two factors to differ * by a large percentage: p=3 and q large would result in a easy * to factor Blum modulus. Thus we select sizes that differ by * up to 6% but not (significantly) greater than 6%. * * Again, the ability (or lack thereof) to factor 'n=p*q' does not * directly relate to the strength of the Blum generator. We * selected n=p*q > 2^1024 mainly because 1024 was a power of 2. * Secondly 1024 the first power of 2 beyond 512 which bit size at * or near the general factor limit a of Jan 1996. * * Using the '6% rule' above, a Blum modulus n=p*q > 2^1024 would have two * Blum factors p > 2^482 and q > 2^542. This is because 482+542 = 1024. * The difference 542-482 is ~5.86% of 1024, and is the largest difference * that is < 6%. * * The default Blum modulus is the product of two Blum probable primes * that were selected by the Rand Book of Random Numbers. Using the '6% rule', * a default Blum modulus n=p*q > 2^1024 would be satisfied if p were * 146 decimal digits and q were 164 decimal digits in length. We restate * the sizes in decimal digits because the Rand Book of Random Numbers is a * book of decimal digits. Using the first 146 rand digits as a * starting search point for 'p', and the next 164 digits for a starting * search point for 'q'. * * (* * * setup the search points (lines split for readability) * *) * ip = 10097325337652013586346735487680959091173929274945 * 37542048056489474296248052403720636104020082291665 * 0842268953196450930323209025601595334764350803; * iq = 36069901902529093767071538311311658867674397044362 * 76591280799970801573614764032366539895116877121717 * 68336606574717340727685036697361706581339885111992 * 91703106010805; * * (* * * find the first Blum prime * *) * fp = int((ip-1)/2); * do { * fp = nextcand(fp+2, 25, 0, 3, 4); * p = 2*fp+1; * } while (ptest(p, 25) == 0); * * (* * * find the 2nd Blum prime * *) * fq = int((iq-1)/2); * do { * fq = nextcand(fq+2, 25, 0, 3, 4); * q = 2*fq+1; * } while (ptest(q, 25) == 0); * * The above script produces the Blum probable primes and initial quadratic * residue (line wrapped for readability): * * p = 0x33c08d08248479497fe557b0e013b1beb51957cb441840f95d199e40fa9 * 19faee2444d687775cb391bc703d710bd05f0cb0670b0bd49430ec8f9393e * 7 * * q = 0xa05970f94cdf85f9773f7772636d591c0575bf5873299b4f48f873529f8 * 85e91577802c65d629e809e797d130254afb7b1e8a4d7afe4f18facec41c2 * 7f2bcfa1496e53a7 * * These Blum primes were found after 43m 56s of CPU time on a 150 Mhz IP22 * R4400 version 5.0 processor. The first Blum prime 'p' was 411284 higher * than the initial search value 'ip'. The second Blum prime 'q' was 87282 * higher than the initial starting 'iq'. * * The product of the two Blum primes results in a 1026 bit Blum modulus of: * * n = 0x206a6cecc22e947050ffcf5eb53742e0a85433800fcaab4452df182bccf * 72b874f3abaf118b29d64a859cd9c1465796a1cdf061f9bf3374443da6e1c * fc63b7a7bd90dad9a3853642820ab4664a82ae1951779f3d1af9a70bedfd4 * abcd89cdc200cbb917c1f7881fc900163d7a84f5e8e53d5bc5918590c15a4 * 45430bbee7b60b1 * * The selection if the initial quadratic residue comes from the next * unused digits of the Rand Book of Random Numbers. Now the two initial * search values 'ip' and 'iq' used above needed the first 146 digits and * the next 164 digits. Thus we will skip the first 146+164=310 digits * and begin to build in initial search value for a quadratic residue (most * significant digit first) from the Rand Book of Numbers digits until we * have a value that is within the range: * * [2^(binsize*4/5), 2^(binsize-2)) * * where 2^(binsize-1) < n=p*q <= 2^binsize. Here, binsize is the * smallest power of 2 >= n=p*q. Using this method, we arrive at an * initial search value for the quadratic residue (wrapped for readability): * * ir = 45571824063530342614867990743923403097328526977602 * 02051656926866574818730538524718623885796357332135 * 05325470489055357548284682870983491256247379645753 * 03529647783580834282609352034435273884359852017767 * 14905686072210940558609709343350500739981180505431 * 39808277325072568248294052420152775678518345299634 * 06288980 * * using the next 308 digits from the Rand Book of Random Numbers. The * (310+309)th digit results in an 'ir' that is outside the range noted above. * * Using pmod(ir, 2, n), we arrive at the initial quadratic residue of the * default Blum generator: * * r = 0x1455b0e84ea73df591501002a7ff7855ef114f4ab34114f7e78208179a7 * 8b722591126b68629b8e840ef5408f7d46db41b438fba4bfd69a6fa7635ab * fbbfde64a198d62cfab4f03f43fb1f402c63202c7beb0b023034f27c6729b * 672fc0ac85e14c610137e7766c67f1ea9cf75e0d60339e254065642e37b7f * 4b9462d0687e467 * * In the above process, we selected primes of the form: * * 2*x + 1 x is also prime * * because Blum generators with modulus 'n=p*q' have a period: * * lambda(n) = lcm(factors of p-1 & q-1) * * since 'p' and 'q' are both odd, 'p-1' and 'q-1' have 2 as * a factor. The calc script above ensures that '(p-1)/2' and * '(q-1)/2' are probable prime, thus maximizing the period * of the default generator to: * * lambda(n) = lcm(2,2,fp,fq) = 2*fp*fq = ~2*(p/2)*(q/2) = ~n/2 * * The process above resulted in a default generator Blum modulus n > 2^1024 * with period of at least 2^1023 bits. To be exact, the period of the * default Blum generator is: * * 0x9edee4226e56e1ba24e6b20180648967ae10bba409a1a1975e95c9c4be0dc9b7 * 4af2d44bd15a117f6a108d043418c88957f4a3e2c10c3267b44332c7445b6a0c * dcdc2ebefec6f8fa48aff8c9867769c4bfa790acba7e7aaa4b90bc2bff5ba65f * 9e652919cfc51edd706b52c884cf56e8fbd378c1f561c651a9f7000180481e0d2 * * which is approximately: * * ~1.785 * 10^309 * * This period is more than long enough for computationally tractable tasks. * **** * * 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 of Random Numbers 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. * * When using the a55 generator, one may select your own 55 additive * values by calling: * * srand(mat55) * * and avoid using my magic numbers. The randreseed64 process is NOT * applied to the matrix values. Of course, you must pick good additive * 55 values yourself! * * One might object to the complexity of the seed scramble/mapping * via the randreseed64() function. The randreseed64() function maps: * * 0 ==> 0 * 10239951819489363767 ==> 1363042948800878693 * * so that srand(0) does the default action and randreseed64() remains * an 1-to-1 and onto map. Thus calling srand(0) 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 the above script that produced a 1028 bit * Blum modulus. As far as I know, 310 digits (1028 bits) is beyond the * state of the art of Number Theory and Computation as of 01 Jan 96. * It is possible in the future that 310 digit products of two primes could * come within reach of factoring 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? * * If all the above fails to pacify the truly paranoid, then one may * select your own modulus and initial quadratic residue by calling: * * srandom(s, n); * * Of course, you will need to select a correct Blum modulus 'n' as the * product of two Blum primes (both 3 mod 4) and with a long period (where * lcm(factors of one less than the two Blum primes) is large) and an * initial quadratic residue 's' that is hard to guess (a large value * from the range [n^(4/5), n/2) selected at random. * * A simple way to seed the generator would be to: * * config("srandom", 0); * srandom(s, nextcand(ip,25,0,3,4)*nextcand(iq,25,0,3,4)) * * where 'ip' and 'iq' are large integers that are unlikely to be 'guessed' * and where they are selected randomly from the [2^(binsize*4/5), * 2^(binsize-2)) where 2^(binsize-1) < n=p*q <= 2^binsize. * * Of course you can increase the '25' value if 1 of 4^25 odds of a * non-prime are too probable for you. The '0' means don't skip any * tests* and the final '3,4' means to select only Blum candidates. * The config("srandom", 0) call turns off srandom checks on the 'n'' * argument. This is OK to do in the above case because the nextcand() * calls ensure proper Blum prime selection. * * The problem with the above call is that the period of the Blum generator * could be small if 'p' and 'q' have lots of small prime factors in common. * * A better way to do seed the Blum generator yourself is to use the * seedrandom(seed1, seed2, size [,tests]) function from "seedrandom.cal" * with the args: * * seed1 - seed rand() to search for 'p', select from [2^64, 2^308) * seed2 - seed rand() to search for 'q', select from [2^64, 2^308) * size - minimum bit size of the Blum modulus 'n=p*q' * tests - optional arg for number of pseudo prime tests (default is 25) * * The seedrandom() function ensures that the Blum generator produced * has a maximal period. * * The following call will seed the Blum generator to an identical state * produced by srandom(0): * * seedrandom(10097325337652013586346735487680959091173929274945, * 37542048056489474296248052403720636104020082291665, * 1024) * * The seedrandom() function in seedrandom.cal makes use of the rand() * additive 55 generator. If you object to using rand(), you could * substitute your own generator (by rewriting the function). * * Last, one could use some external random source to select starting * search points for 'p', 'q' and the quadratic residue. One way to * do this is: * * fp = int((ip-1)/2); * do { * fp = nextcand(fp+2, tests, 0, 3, 4); * p = 2*fp+1; * } while (ptest(p, tests) == 0); * fq = int((iq-1)/2); * do { * fq = nextcand(fq+2, tests, 0, 3, 4); * q = 2*fq+1; * } while (ptest(q, tests) == 0); * srandom(pmod(ir,2,p*q), p*q); * * where 'tests' is the number of pseudo prime tests that a candidate must * pass before being considered a probable prime (must be >0, perhaps 25), and * where 'ip' is the initial search location for the Blum prime 'p', and * where 'iq' is the initial search location for the Blum prime 'q', and * where 'ir' is the initial Blum quadratic residue generator. The 'ir' * value should be a random value in the range [2^(binsize*4/5), 2^(binsize-2)) * where 2^(binsize-1) < n=p*q <= 2^binsize. * * Your external generator would need to generate 'ip', 'iq' and 'ir'. * While any value for 'ip' and 'iq will do (provided that their product * is large enough to meet your modulus needs), 'ir' should be selected * to avoid values near 0 or near 'n' (or ip*iq). * * The Blum moduli used with the pre-defined generators (via the call * srandom(seed, 0 0 (so that srand(0) acts as default) * randreseed64() is an 1-to-1 and onto map * * 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 Random 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 Random Numbers. Because m=2^64 is 20 decimal digits long, * we will search the Rand Book of Random 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 of Random Numbers 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) * * We can determine which 0<=y 10239951819489363767 * * 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 pseudo random number generator. This function is * intended to be used internally by sa55rand() and sshufrand(). */ static void randreseed64(ZVALUE seed, ZVALUE *res) { ZVALUE t; /* temp value */ ZVALUE chunk; /* processed 64 bit chunk value */ ZVALUE seed64; /* seed mod 2^64 */ HALF *v64; /* 64 bit array of HALFs */ long chunknum; /* 64 bit chunk number */ /* * quickly return 0 if seed is 0 */ if (ziszero(seed) || seed.len <= 0) { itoz(0, res); return; } /* * allocate result */ seed.sign = 0; /* use the value of seed */ res->len = (int)(((seed.len+SHALFS-1) / SHALFS) * SHALFS); res->v = alloc(res->len); res->sign = 0; memset(res->v, 0, res->len*sizeof(HALF)); /* default value is 0 */ /* * process 64 bit chunks until done */ chunknum = 0; while (!zislezero(seed)) { /* * grab the lower 64 bits of seed */ if (zge64b(seed)) { v64 = alloc(SHALFS); memcpy(v64, seed.v, SHALFS*sizeof(HALF)); seed64.v = v64; seed64.len = SHALFS; seed64.sign = 0; } else { zcopy(seed, &seed64); } zshiftr(seed, SBITS); ztrim(&seed); ztrim(&seed64); /* * do nothing if chunk is zero */ if (ziszero(seed64)) { ++chunknum; zfree(seed64); continue; } /* * Compute the linear congruence generator map: * * X1 <-- (a*X0 + c) mod m * * in other words: * * chunk == (a_val*seed + c_val) mod 2^64 */ zmul(seed64, a_val, &t); zfree(seed64); zadd(t, c_val, &chunk); zfree(t); /* * form chunk mod 2^64 */ if (chunk.len > SHALFS) { /* result is too large, reduce to 64 bits */ v64 = alloc(SHALFS); memcpy(v64, chunk.v, SHALFS*sizeof(HALF)); free(chunk.v); chunk.v = v64; chunk.len = SHALFS; ztrim(&chunk); } /* * 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 (ziszero(chunk)) { /* load 1363042948800878693 instead of 0 */ zcopy(c_val, &chunk); memcpy(res->v+(chunknum*SHALFS), c_val.v, c_val.len*sizeof(HALF)); /* * load the 64 bit chunk into the result */ } else { memcpy(res->v+(chunknum*SHALFS), chunk.v, chunk.len*sizeof(HALF)); } ++chunknum; zfree(chunk); } ztrim(res); } /* * zsrand - seed the a55 generator * * given: * pseed - ptr to seed of the generator or NULL * pmat55 - additive 55 state table or NULL * * returns: * previous a55 state */ RAND * zsrand(CONST ZVALUE *pseed, CONST MATRIX *pmat55) { RAND *ret; /* previous a55 state */ CONST VALUE *v; /* value from a passed matrix */ ZVALUE zscram; /* scrambled 64 bit seed */ ZVALUE seed; /* to hold *pseed */ FULL shufxor[SLEN]; /* zshufxor as an 64 bit array of FULLs */ long indx; /* index to shuffle slots for seeding */ int i; /* * firewall */ if (pseed != NULL && zisneg(*pseed)) { math_error("neg seeds for srand reserved for future use"); /*NOTREACHED*/ } /* * initialize state if first call */ if (!a55.seeded) { a55 = init_a55; } /* * save the current state to return later */ ret = (RAND *)malloc(sizeof(RAND)); if (ret == NULL) { math_error("cannot allocate RAND state"); /*NOTREACHED*/ } *ret = a55; /* * if call was srand(), just return current state */ if (pseed == NULL && pmat55 == NULL) { return ret; } /* * if call is srand(0), initialize and return quickly */ if (pmat55 == NULL && ziszero(*pseed)) { a55 = init_a55; return ret; } /* * clear buffered bits, initialize pointers */ a55.seeded = 0; /* not seeded now */ a55.j = INIT_J-1; a55.k = INIT_K-1; a55.bits = 0; memset(a55.buffer, 0, sizeof(a55.buffer)); /* * load additive table * * We will load the default additive table unless we are passed a * matrix. If we are passed a matrix, we will load the first 55 * values mod 2^64 instead. */ if (pmat55 == NULL) { memcpy(a55.slot, additive, sizeof(additive)); } else { /* * use the first 55 entries from the matrix arg */ if (pmat55->m_size < A55) { math_error("matrix for srand has < 55 elements"); /*NOTREACHED*/ } for (v=pmat55->m_table, i=0; i < A55; ++i, ++v) { /* reject if not integer */ if (v->v_type != V_NUM || qisfrac(v->v_num)) { math_error("matrix for srand must contain ints"); /*NOTREACHED*/ } /* load table element from matrix element mod 2^64 */ SLOAD(a55, i, v->v_num->num); } } /* * scramble the seed in 64 bit chunks */ if (pseed != NULL) { seed.sign = pseed->sign; seed.len = pseed->len; seed.v = alloc(seed.len); zcopyval(*pseed, seed); randreseed64(seed, &zscram); zfree(seed); } /* * xor additive table with the rehashed lower 64 bits of seed */ if (pseed != NULL && !ziszero(zscram)) { /* xor additive table with lower 64 bits of seed */ SMOD64(shufxor, zscram); for (i=0; i < A55; ++i) { SXOR(a55, i, shufxor); } } /* * shuffle additive 55 table according to seed, if passed */ if (pseed != NULL && zge64b(zscram)) { /* prepare the seed for additive slot shuffling */ zshiftr(zscram, 64); ztrim(&zscram); /* shuffle additive table */ for (i=A55-1; i > 0 && !zislezero(zscram); --i) { /* determine what we will swap with */ indx = zdivi(zscram, i+1, &zscram); /* do nothing if swap with itself */ if (indx == i) { continue; } /* swap slot[i] with slot[indx] */ SSWAP(a55, i, indx); } zfree(zscram); } /* * load the shuffle table * * We will generate SHUFCNT entries from the additive 55 slots * and fill the shuffle table in consecutive order. */ for (i=0; i < SHUFCNT; ++i) { /* bump j and k */ if (++a55.j >= A55) { a55.j = 0; } if (++a55.k >= A55) { a55.k = 0; } /* slot[k] += slot[j] */ SADD(a55, a55.k, a55.j); /* shuf[i] = slot[k] */ SSHUF(a55, i, a55.k); } /* * note that we are seeded */ a55.seeded = 1; /* * return the previous state */ return ret; } /* * zsrandom - seed the Blum generator * * seed > 0, n == NULL: * * Seed the an internal additive 55 shuffle generator, and use it * to produce an initial quadratic residue in the range: * * [2^(binsize*4/5), 2^(binsize-2)) * * where 2^(binsize-1) < n <= 2^binsize and 'n' is the current Blum * modulus. Here, binsize is the smallest power of 2 >= n. * * The follow calc script produces an equivalent effect: * * cur_state = srand(seed); * binsize = highbit(n)+1; (* n is the current Blum modulus *) * r = pmod(rand(1<= 1007: * * If 'n' passes the tests (if applicable) specified by the "srandom" * config value, it becomes the Blum modulus. Any internally buffered * random bits are flushed. * * The initial quadratic residue 'r', is selected as if the following * was executed: * * (* set Blum modulus to newn if allowed by "srandom" config value *) * (* and then set the initial quadratic residue by the next call *) * srandom(n % 2^309); * * The first srand() call seeds the additive 55 shuffle generator * with the lower 309 bits of n. In actual practice, calc uses * an independent internal rand() state value. * * seed > 0, n >= 1007: * * If 'n' passes the tests (if applicable) specified by the "srandom" * config value, it becomes the Blum modulus. Once the Blum modulus * is set, seed is used to seed an internal Additive 55 generator * state which in turn is used to set the initial quadratic residue. * * While not as efficient, this call is equivalent to: * * srandom(0, n); * srandom(seed); * * seed < 0, n >= NULL: * * Reserved for future use. * * any seed, 20 < n < 1007: * * Reserved for future use. * * any seed, n < 0: * * Reserved for future use. * * seed == 0, 0 < n <= 20: * * Seed with one of the predefined Blum moduli. (see the comments * near the top under the section 'INITIALIZATION AND SEEDS') * * seed > 0, 0 < n <= 20: * * Use the same pre-defined Blum moduli 'n' noted above but use 'seed' * to find a different quadratic residue 'r'. * * While not as efficient, this call is equivalent to: * * srandom(0, n); * srandom(seed); * * seed < 0, 0 < n <= 20: * * Use the same pre-defined Blum moduli 'n' noted above but use '-seed' * to compute a different quadratic residue 'r'. * * This call has the same effect as: * * srandom(0, n) * * followed by the setting of the quadratic residue 'r' as follows: * * r = pmod(seed, 2, n) * * where 'n' is the Blum moduli generated by 'srandom(0,newn)' and * 'r' is the new quadratic residue. * * given: * pseed - seed of the generator or NULL * n - ptr to n (Blum modulus), or NULL * * returns: * previous Blum state */ /*XXX - use them*/ /*ARGSUSED*/ RANDOM * zsrandom(CONST ZVALUE seed, CONST ZVALUE *n) { RANDOM *ret; /* previous Blum state */ /* * initialize state if first call */ if (!blum.seeded) { blum = init_blum; zcopy(*(init_blum.n), blum.n); zcopy(*(init_blum.r), blum.r); blum.seeded = 1; } /* * save the current state to return later */ ret = (RANDOM *)malloc(sizeof(RANDOM)); if (ret == NULL) { math_error("cannot allocate RANDOM state"); /*NOTREACHED*/ } /* move the ZVALUES over to ret */ *ret = blum; /* XXX - finish this function */ /* * return the previous state */ return ret; } /* * zsetrand - set the a55 generator state * * given: * state - the state to copy * * returns: * previous a55 state */ RAND * zsetrand(CONST RAND *state) { RAND *ret; /* previous a55 state */ /* * initialize state if first call */ if (!a55.seeded) { a55 = init_a55; } /* * save the current state to return later */ ret = randcopy(&a55); /* * load the new state */ a55 = *state; /* * return the previous state */ return ret; } /* * zsetrandom - set the Blum generator state * * given: * state - the state to copy * * returns: * previous RANDOM state */ RANDOM * zsetrandom(CONST RANDOM *state) { RANDOM *ret; /* previous Blum state */ /* * initialize state if first call */ if (!blum.seeded) { blum = init_blum; zcopy(*(init_blum.n), blum.n); zcopy(*(init_blum.r), blum.r); blum.seeded = 1; } /* * save the current state to return later */ ret = (RANDOM *)malloc(sizeof(RANDOM)); if (ret == NULL) { math_error("cannot allocate RANDOM state"); /*NOTREACHED*/ } /* move the ZVALUES over to ret */ *ret = blum; /* * load the new state */ if (state != NULL) { blum.seeded = 0; /* avoid being caught while copying */ blum.bits = state->bits; blum.buffer = state->buffer; zcopy(*(state->n), blum.n); zcopy(*(state->r), blum.r); blum.seeded = 1; } /* * return the previous state */ return ret; } /* * slotcp - copy up to 64 bits from a 64 bit array of FULLs to some HALFs * * We will copy data from an array of FULLs into an array of HALFs. * The destination within the HALFs is some bit location found in bitstr. * We will attempt to copy 64 bits, but if there is not enough room * (bits not yet loaded) in the destination bit string we will transfer * what we can. * * The src slot is 64 bits long and is stored as an array of FULLs. * When FULL_BITS is 64 the element is 1 FULL, otherwise FULL_BITS * is 32 bits and the element is 2 FULLs. The most significant bit * in the array (highest bit in the last FULL of the array) is to * be transfered to the most significant bit in the destination. * * given: * bitstr - most significant destination bit in a bit string * src - low order FULL in a 64 bit slot * count - number of bits to transfer (must be 0 < count <= 64) * * returns: * number of bits transfered */ static int slotcp(BITSTR *bitstr, FULL *src, int count) { HALF *dh; /* most significant HALF in dest */ int dnxtbit; /* next bit beyond most signif in dh */ int need; /* number of bits we need to transfer */ int ret; /* bits transfered */ /* * determine how many bits we actually need to transfer */ dh = bitstr->loc; dnxtbit = bitstr->bit+1; count &= (SBITS-1); need = (bitstr->len < count) ? bitstr->len : count; /* * prepare for the return * * Note the final bitstr location after we have moved the * position down 'need' bits. */ bitstr->len -= need; bitstr->loc -= need / BASEB; bitstr->bit -= need % BASEB; if (bitstr->bit < 0) { --bitstr->loc; bitstr->bit += BASEB; } ret = need; /* * deal with aligned copies quickly */ if (dnxtbit == BASEB) { if (need == SBITS) { #if 2*FULL_BITS == SBITS *dh-- = (HALF)(src[SLEN-1] >> BASEB); *dh-- = (HALF)(src[SLEN-1]); #endif *dh-- = (HALF)(src[0] >> BASEB); *dh = (HALF)(src[0]); #if 2*FULL_BITS == SBITS } else if (need > FULL_BITS+BASEB) { *dh-- = (HALF)(src[SLEN-1] >> BASEB); *dh-- = (HALF)(src[SLEN-1]); *dh-- = (HALF)(src[0] >> BASEB); *dh = ((HALF)src[0] & highhalf[need-FULL_BITS-BASEB]); } else if (need > FULL_BITS) { *dh-- = (HALF)(src[SLEN-1] >> BASEB); *dh-- = (HALF)(src[SLEN-1]); *dh = ((HALF)(src[0] >> BASEB) & highhalf[need-FULL_BITS]); #endif } else if (need > BASEB) { *dh-- = (HALF)(src[SLEN-1] >> BASEB); *dh = ((HALF)(src[SLEN-1]) & highhalf[need-BASEB]); } else { *dh = ((HALF)(src[SLEN-1] >> BASEB) & highhalf[need]); } return ret; } /* * load the most significant HALF */ if (need >= dnxtbit) { /* fill up the most significant HALF */ *dh-- |= (HALF)(src[SLEN-1] >> (FULL_BITS-dnxtbit)); need -= dnxtbit; } else if (need > 0) { /* we exhaust our need before 1st half is filled */ *dh |= (HALF)((src[SLEN-1] >> (FULL_BITS-need)) << (dnxtbit-need)); return ret; /* our need has been filled */ } else { return ret; /* our need has been filled */ } /* * load the 2nd most significant HALF */ if (need > BASEB) { /* fill up the 2nd most significant HALF */ *dh-- = (HALF)(src[SLEN-1] >> (BASEB-dnxtbit)); need -= BASEB; } else if (need > 0) { /* we exhaust our need before 2nd half is filled */ *dh |= ((HALF)(src[SLEN-1] >> (BASEB-dnxtbit)) & highhalf[need]); return ret; /* our need has been filled */ } else { return ret; /* our need has been filled */ } /* * load the 3rd most significant HALF * * At this point we know that our 3rd HALF will force us * to cross into a second FULL for systems with 32 bit FULLs. * We know this because the aligned case has been previously * taken care of above. * * For systems that have 64 bit FULLs (and 32 bit HALFs) this * is will be our least significant HALF. We also know that * the need must be < BASEB. */ #if FULL_BITS == SBITS *dh |= (((HALF)src[0] & highhalf[dnxtbit+need]) << dnxtbit); #else if (need > BASEB) { /* load the remaining bits from the most signif FULL */ *dh-- = ((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit]) << dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit))); need -= BASEB; } else if (need > 0) { /* load the remaining bits from the most signif FULL */ *dh-- |= (((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit]) << dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit))) & highhalf[need]); return ret; /* our need has been filled */ } else { return ret; /* our need has been filled */ } /* * load the 4th most significant HALF * * At this point, only 32 bit FULLs are operating. */ if (need > BASEB) { /* fill up the 2nd most significant HALF */ *dh-- = (HALF)(src[0] >> (BASEB-dnxtbit)); /* no need todo: need -= BASEB, because we are nearly done */ } else if (need > 0) { /* we exhaust our need before 2nd half is filled */ *dh |= ((HALF)(src[0] >> (BASEB-dnxtbit)) & highhalf[need]); return ret; /* our need has been filled */ } else { return ret; /* our need has been filled */ } /* * load the 5th and least significant HALF * * At this point we know that the need will be satisfied. */ *dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit); #endif return ret; /* our need has been filled */ } /* * slotcp64 - copy 64 bits from a 64 bit array of FULLs to some HALFs * * We will copy data from an array of FULLs into an array of HALFs. * The destination within the HALFs is some bit location found in bitstr. * Unlike slotcp(), this function will always copy 64 bits. * * The src slot is 64 bits long and is stored as an array of FULLs. * When FULL_BITS is 64 this array is 1 FULL, otherwise FULL_BITS * is 32 bits and the array is 2 FULLs. The most significant bit * in the array (highest bit in the last FULL of the array) is to * be transfered to the most significant bit in the destination. * * given: * bitstr - most significant destination bit in a bit string * src - low order FULL in a 64 bit slot * * returns: * number of bits transfered */ static void slotcp64(BITSTR *bitstr, FULL *src) { HALF *dh = bitstr->loc; /* most significant HALF in dest */ int dnxtbit = bitstr->bit+1; /* next bit beyond most signif in dh */ /* * prepare for the return * * Since we are moving the point 64 bits down, we know that * the bit location (bitstr->bit) will remain the same. */ bitstr->len -= SBITS; bitstr->loc -= SBITS/BASEB; /* * deal with aligned copies quickly */ if (dnxtbit == BASEB) { #if 2*FULL_BITS == SBITS *dh-- = (HALF)(src[SLEN-1] >> BASEB); *dh-- = (HALF)(src[SLEN-1]); #endif *dh-- = (HALF)(src[0] >> BASEB); *dh = (HALF)(src[0]); return; } /* * load the most significant HALF */ *dh-- |= (HALF)(src[SLEN-1] >> (FULL_BITS-dnxtbit)); /* * load the 2nd most significant HALF */ *dh-- = (HALF)(src[SLEN-1] >> (BASEB-dnxtbit)); /* * load the 3rd most significant HALF * * At this point we know that our 3rd HALF will force us * to cross into a second FULL for systems with 32 bit FULLs. * We know this because the aligned case has been previously * taken care of above. * * For systems that have 64 bit FULLs (and 32 bit HALFs) this * is will be our least significant HALF. */ #if FULL_BITS == SBITS *dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit); #else /* load the remaining bits from the most signif FULL */ *dh-- = ((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit]) << dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit))); /* * load the 4th most significant HALF * * At this point, only 32 bit FULLs are operating. */ *dh-- = (HALF)(src[0] >> (BASEB-dnxtbit)); /* * load the 5th and least significant HALF * * At this point we know that the need will be satisfied. */ *dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit); #endif } /* * zrandskip - skip s bits * * given: * count - number of bits to be skipped */ void zrandskip(long cnt) { int indx; /* shuffle entry index */ /* * initialize state if first call */ if (!a55.seeded) { a55 = init_a55; } /* * skip required bits in the buffer */ if (a55.bits > 0 && a55.bits <= cnt) { /* just toss the buffer bits */ cnt -= a55.bits; a55.bits = 0; memset(a55.buffer, 0, sizeof(a55.buffer)); } else if (a55.bits > 0 && a55.bits > cnt) { /* buffer contains more bits than we need to toss */ #if FULL_BITS == SBITS a55.buffer[0] <<= cnt; #else if (cnt >= FULL_BITS) { a55.buffer[SLEN-1] = (a55.buffer[0] << cnt); a55.buffer[0] = 0; } else { a55.buffer[SLEN-1] = ((a55.buffer[SLEN-1] << cnt) | (a55.buffer[0] >> (FULL_BITS-cnt))); a55.buffer[0] <<= cnt; } #endif a55.bits -= cnt; return; /* skip need satisfied */ } /* * skip 64 bits at a time */ while (cnt >= SBITS) { /* bump j and k */ if (++a55.j >= A55) { a55.j = 0; } if (++a55.k >= A55) { a55.k = 0; } /* slot[k] += slot[j] */ SADD(a55, a55.k, a55.j); /* we will ignore the output value of a55.slot[indx] */ indx = SINDX(a55, a55.k); cnt -= SBITS; /* store a55.k into a55.slot[indx] */ SSHUF(a55, indx, a55.k); } /* * skip the final bits */ if (cnt > 0) { /* bump j and k */ if (++a55.j >= A55) { a55.j = 0; } if (++a55.k >= A55) { a55.k = 0; } /* slot[k] += slot[j] */ SADD(a55, a55.k, a55.j); /* we will ignore the output value of a55.slot[indx] */ indx = SINDX(a55, a55.k); /* * We know the buffer is empty, so fill it * with any unused bits. Copy SBITS-trans bits * from slot[indx] into buffer. */ a55.bits = (int)(SBITS-cnt); memcpy(a55.buffer, &a55.shuf[indx*SLEN], sizeof(a55.buffer)); /* * shift the buffer bits all the way up to * the most significant bit */ #if FULL_BITS == SBITS a55.buffer[0] <<= cnt; #else if (cnt >= FULL_BITS) { a55.buffer[SLEN-1] = (a55.buffer[0] << cnt); a55.buffer[0] = 0; } else { a55.buffer[SLEN-1] = ((a55.buffer[SLEN-1] << cnt) | (a55.buffer[0] >> (FULL_BITS-cnt))); a55.buffer[0] <<= cnt; } #endif /* store a55.k into a55.slot[indx] */ SSHUF(a55, indx, a55.k); } } /* * zrand - crank the a55 generator for some bits * * given: * count - number of bits required * res - where to place the random bits as ZVALUE */ void zrand(long cnt, ZVALUE *res) { long hlen; /* length of ZVALUE in HALFs */ BITSTR dest; /* destination bit string */ int trans; /* bits transfered */ int indx; /* shuffle entry index */ /* * firewall */ if (cnt <= 0) { if (cnt == 0) { /* zero length random number is always 0 */ itoz(0, res); return; } else { math_error("negative zrand bit count"); /*NOTREACHED*/ } #if LONG_BITS > 32 } else if (cnt > (1L<<31)) { math_error("huge rand bit count in internal zrand function"); /*NOTREACHED*/ #endif } /* * initialize state if first call */ if (!a55.seeded) { a55 = init_a55; } /* * allocate storage */ hlen = (cnt+BASEB-1)/BASEB; res->len = (LEN)hlen; res->v = alloc((LEN)hlen); memset(res->v, 0, hlen*sizeof(HALF)); /* * dest bit string */ dest.len = (int)cnt; dest.loc = res->v + (hlen-1); dest.bit = (int)((cnt-1) % BASEB); /* * load from buffer first */ if (a55.bits > 0) { /* * We know there are only a55.bits in the buffer, so * transfer as much as we can (treating it as a slot) * and return the bit transfer count. */ trans = slotcp(&dest, a55.buffer, a55.bits); /* * If we need to keep bits in the buffer, * shift the buffer bits all the way up to * the most significant unused bit. */ if (trans < a55.bits) { #if FULL_BITS == SBITS a55.buffer[0] <<= trans; #else if (trans >= FULL_BITS) { a55.buffer[SLEN-1] = (a55.buffer[0] << (trans-FULL_BITS)); a55.buffer[0] = 0; } else { a55.buffer[SLEN-1] = ((a55.buffer[SLEN-1] << trans) | (a55.buffer[0] >> (FULL_BITS-trans))); a55.buffer[0] <<= trans; } #endif } /* note that we have fewer bits in the buffer */ a55.bits -= trans; } /* * spin the generator until we need less than 64 bits * * The buffer did not contain enough bits, so we crank the * a55 generator and load then 64 bits at a time. */ while (dest.len >= SBITS) { /* bump j and k */ if (++a55.j >= A55) { a55.j = 0; } if (++a55.k >= A55) { a55.k = 0; } /* slot[k] += slot[j] */ SADD(a55, a55.k, a55.j); /* select slot index to output */ indx = SINDX(a55, a55.k); /* move up to 64 bits from slot[indx] to dest */ slotcp64(&dest, &a55.shuf[indx*SLEN]); /* store a55.k into a55.slot[indx] */ SSHUF(a55, indx, a55.k); } /* * spin the generator one last time to fill out the remaining need */ if (dest.len > 0) { /* bump j and k */ if (++a55.j >= A55) { a55.j = 0; } if (++a55.k >= A55) { a55.k = 0; } /* slot[k] += slot[j] */ SADD(a55, a55.k, a55.j); /* select slot index to output */ indx = SINDX(a55, a55.k); /* move up to 64 bits from slot[indx] to dest */ trans = slotcp(&dest, &a55.shuf[indx*SLEN], dest.len); /* buffer up unused bits if we are done */ if (trans != SBITS) { /* * We know the buffer is empty, so fill it * with any unused bits. Copy SBITS-trans bits * from slot[indx] into buffer. */ a55.bits = SBITS-trans; memcpy(a55.buffer, &a55.shuf[indx*SLEN], sizeof(a55.buffer)); /* * shift the buffer bits all the way up to * the most significant bit */ #if FULL_BITS == SBITS a55.buffer[0] <<= trans; #else if (trans >= FULL_BITS) { a55.buffer[SLEN-1] = (a55.buffer[0] << (trans-FULL_BITS)); a55.buffer[0] = 0; } else { a55.buffer[SLEN-1] = ((a55.buffer[SLEN-1] << trans) | (a55.buffer[0] >> (FULL_BITS-trans))); a55.buffer[0] <<= trans; } #endif } /* store a55.k into a55.slot[indx] */ SSHUF(a55, indx, a55.k); } res->sign = 0; ztrim(res); } /* * zrandrange - generate a random value in the range [low, high) * * given: * low - low value of range * high - beyond end of range * res - where to place the random bits as ZVALUE */ void zrandrange(CONST ZVALUE low, CONST ZVALUE high, ZVALUE *res) { ZVALUE range; /* high-low */ ZVALUE rval; /* random value [0, 2^bitlen) */ ZVALUE rangem1; /* range - 1 */ long bitlen; /* smallest power of 2 >= diff */ /* * firewall */ if (zrel(low, high) >= 0) { math_error("srand low range >= high range"); /*NOTREACHED*/ } /* * determine the size of the random number needed */ zsub(high, low, &range); if (zisone(range)) { zfree(range); *res = low; return; } zsub(range, _one_, &rangem1); bitlen = 1+zhighbit(rangem1); zfree(rangem1); /* * generate a random value between [0, diff) * * 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). */ rval.v = NULL; do { if (rval.v != NULL) { zfree(rval); } zrand(bitlen, &rval); } while (zrel(rval, range) >= 0); /* * add in low value to produce the range [0+low, diff+low) * which is the range [low, high) */ zadd(rval, low, res); zfree(rval); zfree(range); } /* * irand - generate a random long in the range [0, s) * * given: * s - limit of the range * * returns: * random long in the range [0, s) */ long irand(long s) { ZVALUE z1, z2; long res; if (s <= 0) { math_error("Non-positive argument for irand()"); /*NOTREACHED*/ } if (s == 1) return 0; itoz(s, &z1); zrandrange(_zero_, z1, &z2); res = ztoi(z2); zfree(z1); zfree(z2); return res; } /* * randcopy - make a copy of an a55 state * * given: * state - the state to copy * * returns: * a malloced copy of the state */ RAND * randcopy(CONST RAND *state) { RAND *ret; /* return copy of state */ /* * malloc state */ ret = (RAND *)malloc(sizeof(RAND)); if (ret == NULL) { math_error("can't allocate RAND state"); /*NOTREACHED*/ } *ret = *state; /* * return copy */ return ret; } /* * randomcopy - make a copy of a Blum state * * given: * state - the state to copy * * returns: * a malloced copy of the state */ RANDOM * randomcopy(CONST RANDOM *state) { RANDOM *ret; /* return copy of state */ /* * malloc state */ ret = (RANDOM *)malloc(sizeof(RANDOM)); if (ret == NULL) { math_error("can't allocate RANDOM state"); /*NOTREACHED*/ } /* * clone data */ *ret = *state; if (state->r->v == NULL) { ret->r->v = NULL; } else { zcopy(*(state->r), ret->r); } if (state->n->v == NULL) { ret->n->v = NULL; } else { zcopy(*(state->n), ret->n); } /* * return copy */ return ret; } /* * randfree - free an a55 state * * given: * state - the state to free */ void randfree(RAND *state) { /* free it */ free(state); } /* * randomfree - free a Blum state * * given: * state - the state to free */ void randomfree(RANDOM *state) { /* free the values */ state->seeded = 0; zfree(*state->n); zfree(*state->r); /* free it */ free(state); } /* * randcmp - compare two a55 states * * given: * s1 - first state to compare * s2 - second state to compare * * return: * TRUE if states differ */ BOOL randcmp(CONST RAND *s1, CONST RAND *s2) { /* * assume uninitialized state == the default seeded state */ if (!s1->seeded) { if (!s2->seeded) { /* uninitialized == uninitialized */ return TRUE; } else { /* uninitialized only equals default state */ return randcmp(s2, &init_a55); } } else if (!s2->seeded) { if (!s1->seeded) { /* uninitialized == uninitialized */ return TRUE; } else { /* uninitialized only equals default state */ return randcmp(s1, &init_a55); } } /* compare states */ return (BOOL)(memcmp(s1, s2, sizeof(RAND)) != 0); } /* * randomcmp - compare two Blum states * * given: * s1 - first state to compare * s2 - second state to compare * * return: * TRUE if states differ */ BOOL randomcmp(CONST RANDOM *s1, CONST RANDOM *s2) { /* * assume uninitialized state == the default seeded state */ if (!s1->seeded) { if (!s2->seeded) { /* uninitialized == uninitialized */ return TRUE; } else { /* uninitialized only equals default state */ return randomcmp(s2, &post_init_blum); } } else if (!s2->seeded) { /* uninitialized only equals default state */ return randomcmp(s1, &post_init_blum); } /* * compare operating mask parameters */ if ((s1->loglogn != s2->loglogn) || (s1->mask != s2->mask)) { return FALSE; } /* * compare bit buffer */ if ((s1->bits != s2->bits) || (s1->buffer != s2->buffer)) { return FALSE; } /* * compare quadratic residues */ if (!zcmp(*(s1->r), *(s2->r))) { return FALSE; } /* * compare moduli */ if (!zcmp(*(s1->n), *(s2->n))) { return FALSE; } /* * they are equal */ return TRUE; } /* * randprint - print an a55 state * * given: * state - state to print * flags - print flags passed from printvalue() in value.c */ /*ARGSUSED*/ void randprint(CONST RAND *state, int flags) { math_str("RAND state"); } /* * randomprint - print a Blum state * * given: * state - state to print * flags - print flags passed from printvalue() in value.c */ /*ARGSUSED*/ void randomprint(CONST RANDOM *state, int flags) { math_str("RANDOM state"); }