home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-07 | 58.4 KB | 1,805 lines |
- Newsgroups: comp.sources.unix
- From: dbell@canb.auug.org.au (David I. Bell)
- Subject: v27i143: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part16/19
- References: <1.755316719.21314@gw.home.vix.com>
- Sender: unix-sources-moderator@gw.home.vix.com
- Approved: vixie@gw.home.vix.com
-
- Submitted-By: dbell@canb.auug.org.au (David I. Bell)
- Posting-Number: Volume 27, Issue 143
- Archive-Name: calc-2.9.0/part16
-
- #!/bin/sh
- # this is part 16 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file calc2.9.0/lib/README continued
- #
- CurArch=16
- if test ! -r s2_seq_.tmp
- then echo "Please unpack part 1 first!"
- exit 1; fi
- ( read Scheck
- if test "$Scheck" != $CurArch
- then echo "Please unpack part $Scheck next!"
- exit 1;
- else exit 0; fi
- ) < s2_seq_.tmp || exit 1
- echo "x - Continuing file calc2.9.0/lib/README"
- sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/lib/README
- X
- X qpi(epsilon)
- X
- X Calculate pi within the specified epsilon using the quartic convergence
- X iteration.
- X
- X
- Xpollard.cal
- X
- X factor(N, N, ai, af)
- X
- X Factor using Pollard's p-1 method.
- X
- X
- Xpoly.cal
- X
- X Calculate with polynomials of one variable. There are many functions.
- X Read the documentation in the library file.
- X
- X
- Xpsqrt.cal
- X
- X psqrt(u, p)
- X
- X Calculate square roots modulo a prime
- X
- X
- Xquat.cal
- X
- X quat(a, b, c, d)
- X quat_print(a)
- X quat_norm(a)
- X quat_abs(a, e)
- X quat_conj(a)
- X quat_add(a, b)
- X quat_sub(a, b)
- X quat_inc(a)
- X quat_dec(a)
- X quat_neg(a)
- X quat_mul(a, b)
- X quat_div(a, b)
- X quat_inv(a)
- X quat_scale(a, b)
- X quat_shift(a, b)
- X
- X Calculate using quaternions of the form: a + bi + cj + dk. In these
- X functions, quaternians are manipulated in the form: s + v, where
- X s is a scalar and v is a vector of size 3.
- X
- X
- Xregress.cal
- X
- X Test the correct execution of the calculator by reading this library file.
- X Errors are reported with '****' mssages, or worse. :-)
- X
- X
- Xsolve.cal
- X
- X solve(low, high, epsilon)
- X
- X Solve the equation f(x) = 0 to within the desired error value for x.
- X The function 'f' must be defined outside of this routine, and the low
- X and high values are guesses which must produce values with opposite signs.
- X
- X
- Xsumsq.cal
- X
- X ss(p)
- X
- X Determine the unique two positive integers whose squares sum to the
- X specified prime. This is always possible for all primes of the form
- X 4N+1, and always impossible for primes of the form 4N-1.
- X
- X
- Xsurd.cal
- X
- X surd(a, b)
- X surd_print(a)
- X surd_conj(a)
- X surd_norm(a)
- X surd_value(a, xepsilon)
- X surd_add(a, b)
- X surd_sub(a, b)
- X surd_inc(a)
- X surd_dec(a)
- X surd_neg(a)
- X surd_mul(a, b)
- X surd_square(a)
- X surd_scale(a, b)
- X surd_shift(a, b)
- X surd_div(a, b)
- X surd_inv(a)
- X surd_sgn(a)
- X surd_cmp(a, b)
- X surd_rel(a, b)
- X
- X Calculate using quadratic surds of the form: a + b * sqrt(D).
- X
- X
- Xunitfrac.cal
- X
- X unitfrac(x)
- X
- X Represent a fraction as sum of distinct unit fractions.
- X
- X
- Xvarargs.cal
- X
- X sc(a, b, ...)
- X
- X Example program to use 'varargs'. Program to sum the cubes of all
- X the specified numbers.
- SHAR_EOF
- echo "File calc2.9.0/lib/README is complete"
- chmod 0644 calc2.9.0/lib/README || echo "restore of calc2.9.0/lib/README fails"
- set `wc -c calc2.9.0/lib/README`;Sum=$1
- if test "$Sum" != "5516"
- then echo original size 5516, current size $Sum;fi
- echo "x - extracting calc2.9.0/lib/bernoulli.cal (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/lib/bernoulli.cal &&
- X/*
- X * Copyright (c) 1993 David I. Bell
- X * Calculate the Nth Bernoulli number B(n).
- X * This uses the following symbolic formula to calculate B(n):
- X *
- X * (b+1)^(n+1) - b^(n+1) = 0
- X *
- X * where b is a dummy value, and each power b^i gets replaced by B(i).
- X * For example, for n = 3:
- X * (b+1)^4 - b^4 = 0
- X * b^4 + 4*b^3 + 6*b^2 + 4*b + 1 - b^4 = 0
- X * 4*b^3 + 6*b^2 + 4*b + 1 = 0
- X * 4*B(3) + 6*B(2) + 4*B(1) + 1 = 0
- X * B(3) = -(6*B(2) + 4*B(1) + 1) / 4
- X *
- X * The combinatorial factors in the expansion of the above formula are
- X * calculated interatively, and we use the fact that B(2i+1) = 0 if i > 0.
- X * Since all previous B(n)'s are needed to calculate a particular B(n), all
- X * values obtained are saved in an array for ease in repeated calculations.
- X */
- Xstatic Bnmax;
- Xstatic mat Bn[1001];
- X
- X
- Xdefine B(n)
- X{
- X local nn, np1, i, sum, mulval, divval, combval;
- X
- X if (!isint(n) || (n < 0))
- X quit "Non-negative integer required for Bernoulli";
- X
- X if (n == 0)
- X return 1;
- X if (n == 1)
- X return -1/2;
- X if (isodd(n))
- X return 0;
- X if (n > 1000)
- X quit "Very large Bernoulli";
- X
- X if (n <= Bnmax)
- X return Bn[n];
- X
- X for (nn = Bnmax + 2; nn <= n; nn+=2) {
- X np1 = nn + 1;
- X mulval = np1;
- X divval = 1;
- X combval = 1;
- X sum = 1 - np1 / 2;
- X for (i = 2; i < np1; i+=2) {
- X combval = combval * mulval-- / divval++;
- X combval = combval * mulval-- / divval++;
- X sum += combval * Bn[i];
- X }
- X Bn[nn] = -sum / np1;
- X }
- X Bnmax = n;
- X return Bn[n];
- X}
- X
- Xglobal lib_debug;
- Xif (lib_debug >= 0) {
- X print "B(n) defined";
- X}
- SHAR_EOF
- chmod 0644 calc2.9.0/lib/bernoulli.cal || echo "restore of calc2.9.0/lib/bernoulli.cal fails"
- set `wc -c calc2.9.0/lib/bernoulli.cal`;Sum=$1
- if test "$Sum" != "1492"
- then echo original size 1492, current size $Sum;fi
- echo "x - extracting calc2.9.0/lib/bigprime.cal (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/lib/bigprime.cal &&
- X/*
- X * Copyright (c) 1993 David I. Bell
- X * Permission is granted to use, distribute, or modify this source,
- X * provided that this copyright notice remains intact.
- X *
- X * A prime test, base a, on p*2^x+1 for even x>m.
- X */
- X
- Xdefine bigprime(a, m, p)
- X{
- X local n1, n;
- X
- X n1 = 2^m * p;
- X for (;;) {
- X m++;
- X n1 += n1;
- X n = n1 + 1;
- X if (isodd(m))
- X continue;
- X print m;
- X if (pmod(a, n1 / 2, n) != n1)
- X continue;
- X if (pmod(a, n1 / p, n) == 1)
- X continue;
- X print " " : n;
- X }
- X}
- X
- Xglobal lib_debug;
- Xif (lib_debug >= 0) {
- X print "bigprime(a, m, p) defined";
- X}
- SHAR_EOF
- chmod 0644 calc2.9.0/lib/bigprime.cal || echo "restore of calc2.9.0/lib/bigprime.cal fails"
- set `wc -c calc2.9.0/lib/bigprime.cal`;Sum=$1
- if test "$Sum" != "555"
- then echo original size 555, current size $Sum;fi
- echo "x - extracting calc2.9.0/lib/bindings (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/lib/bindings &&
- X# Default key bindings for calc line editing functions
- X
- Xmap base-map
- Xdefault insert-char
- X^@ set-mark
- X^A start-of-line
- X^B backward-char
- X^D delete-char
- X^E end-of-line
- X^F forward-char
- X^H backward-kill-char
- X^J new-line
- X^K kill-line
- X^L refresh-line
- X^M new-line
- X^N forward-history
- X^O save-line
- X^P backward-history
- X^R reverse-search
- X^T swap-chars
- X^U flush-input
- X^V quote-char
- X^W kill-region
- X^Y yank
- X^? backward-kill-char
- X^[ ignore-char esc-map
- X
- Xmap esc-map
- Xdefault ignore-char base-map
- XG start-of-line
- XH backward-history
- XP forward-history
- XK backward-char
- XM forward-char
- XO end-of-line
- XS delete-char
- Xg goto-line
- Xs backward-word
- Xt forward-word
- Xd forward-kill-word
- Xu uppercase-word
- Xl lowercase-word
- Xh list-history
- X^[ flush-input
- X[ arrow-key
- SHAR_EOF
- chmod 0644 calc2.9.0/lib/bindings || echo "restore of calc2.9.0/lib/bindings fails"
- set `wc -c calc2.9.0/lib/bindings`;Sum=$1
- if test "$Sum" != "730"
- then echo original size 730, current size $Sum;fi
- echo "x - extracting calc2.9.0/lib/chrem.cal (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/lib/chrem.cal &&
- X/*
- X * chrem - Chinese remainder theorem/problem solver
- X *
- X * When possible, chrem finds solutions for x of a set of congruences
- X * of the form:
- X *
- X * x = r1 (mod m1)
- X * x = r2 (mod m2)
- X * ...
- X *
- X * where the residues r1, r2, ... and the moduli m1, m2, ... are
- X * given integers. The Chinese remainder theorem states that if
- X * m1, m2, ... are relatively prime in pairs, the above congruences
- X * have a unique solution modulo m1 * m2 * ... If m1, m2, ...
- X * are not relatively prime in pairs, it is possible that no solution
- X * exists. If solutions exist, the general solution is expressible as:
- X *
- X * x = r (mod m)
- X *
- X * where m = lcm(m1,m2,...), and if m > 0, 0 <= r < m. This
- X * solution may be interpreted as:
- X *
- X * x = r + k * m [[NOTE 1]]
- X *
- X * where k is an arbitrary integer.
- X *
- X ***
- X *
- X * usage:
- X *
- X * chrem(r1,m1 [,r2,m2, ...])
- X *
- X * r1, r2, ... remainder integers or null values
- X * m1, m2, ... moduli integers
- X *
- X * chrem(r_list, [m_list])
- X *
- X * r_list list (r1,r2, ...)
- X * m_list list (m1,m2, ...)
- X *
- X * If m_list is omitted, then 'defaultmlist' is used.
- X * This default list is a global value that may be changed
- X * by the user. Initially it is the first 8 primes.
- X *
- X * If a remainder is null(), then the corresponding congruence is
- X * ignored. This is useful when working with a fixed list of moduli.
- X *
- X * If there are more remainders than moduli, then the later moduli are
- X * ignored.
- X *
- X * The moduli may be any integers, not necessarily relatively prime in
- X * pairs (as required for the Chinese remainder theorem). Any moduli
- X * may be zero; x = r (mod 0) has the meaning of x = r.
- X *
- X * returns:
- X *
- X * If args were integer pairs:
- X *
- X * r ('r' is defined above, see [[NOTE 1]])
- X *
- X * If 1 or 2 list args were given:
- X *
- X * (r, m) ('r' and 'm' are defined above, see [[NOTE 1]])
- X *
- X * NOTE: In all cases, null() is returned if there is no solution.
- X *
- X ***
- X *
- X * This function may be used to solve the following historical problems:
- X *
- X * Sun-Tsu, 1st century A.D.
- X *
- X * To find a number for which the reminders after division by 3, 5, 7
- X * are 2, 3, 2, respectively:
- X *
- X * chrem(2,3,3,5,2,7) ---> 23
- X *
- X * Fibonacci, 13th century A.D.
- X *
- X * To find a number divisible by 7 which leaves remainder 1 when
- X * divided by 2, 3, 4, 5, or 6:
- X *
- X *
- X * chrem(list(0,1,1,1,1,1),list(7,2,3,4,5,6)) ---> (301,420)
- X *
- X * i.e., any value that is 301 mod 420.
- X *
- X * Written by: Ernest W Bowen <ernie@neumann.une.edu.au>
- X * Interface by: Landon Curt Noll <chongo@toad.com>
- X */
- X
- Xstatic defaultmlist = list(2,3,5,7,11,13,17,19); /* The first eight primes */
- X
- Xdefine chrem()
- X{
- X local argc; /* number of args given */
- X local rlist; /* reminder list - ri */
- X local mlist; /* modulus list - mi */
- X local list_args; /* true => args given are lists, not r1,m1, ... */
- X local m,z,r,y,d,t,x,u,i;
- X
- X /*
- X * parse args
- X */
- X argc = param(0);
- X if (argc == 0) {
- X quit "usage: chrem(r1,m1 [,r2,m2 ...]) or chrem(r_list, m_list)";
- X }
- X list_args = islist(param(1));
- X if (list_args) {
- X rlist = param(1);
- X mlist = (argc == 1) ? defaultmlist : param(2);
- X if (size(rlist) > size(mlist)) {
- X quit "too many residues";
- X }
- X } else {
- X if (argc % 2 == 1) {
- X quit "odd number integers given";
- X }
- X rlist = list();
- X mlist = list();
- X for (i=1; i <= argc; i+=2) {
- X push(rlist, param(i));
- X push(mlist, param(i+1));
- X }
- X }
- X
- X /*
- X * solve the problem found in rlist & mlist
- X */
- X m = 1;
- X z = 0;
- X while (size(rlist)) {
- X r=pop(rlist);
- X y=abs(pop(mlist));
- X if (r==null())
- X continue;
- X if (m) {
- X if (y) {
- X d = t = z - r;
- X m = lcm(x=m, y);
- X while (d % y) {
- X u = x;
- X x %= y;
- X swap(x,y);
- X if (y==0)
- X return;
- X z += (t *= -u/y);
- X }
- X } else {
- X if ((r % m) != (z % m))
- X return;
- X else {
- X m = 0;
- X z = r;
- X }
- X }
- X } else if (((y) && (r % y != z % y)) || (r != z))
- X return;
- X }
- X if (m) {
- X z %= m;
- X if (z < 0)
- X z += m;
- X }
- X
- X /*
- X * return information as required
- X */
- X if (list_args) {
- X return list(z,m);
- X } else {
- X return z;
- X }
- X}
- X
- Xglobal lib_debug;
- Xif (lib_debug >= 0) {
- X print "chrem(r1,m1 [,r2,m2 ...]) defined";
- X print "chrem(rlist [,mlist]) defined";
- X}
- SHAR_EOF
- chmod 0644 calc2.9.0/lib/chrem.cal || echo "restore of calc2.9.0/lib/chrem.cal fails"
- set `wc -c calc2.9.0/lib/chrem.cal`;Sum=$1
- if test "$Sum" != "4346"
- then echo original size 4346, current size $Sum;fi
- echo "x - extracting calc2.9.0/lib/cryrand.cal (Text)"
- sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/lib/cryrand.cal &&
- X/*
- X * cryrand - cryptographically strong pseudo-random number generator library
- X */
- X/*
- X * Copyright (c) 1993 by Landon Curt Noll. All Rights Reserved.
- X *
- X * Permission to use, copy, modify, and distribute this software and
- X * its documentation for any purpose and without fee is hereby granted,
- X * provided that the above copyright, this permission notice and text
- X * this comment, and the disclaimer below appear in all of the following:
- X *
- X * supporting documentation
- X * source copies
- X * source works derived from this source
- X * binaries derived from this source or from derived source
- X *
- X * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
- X * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- X * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- X * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- X * PERFORMANCE OF THIS SOFTWARE.
- X *
- X * chongo was here /\../\
- X */
- X
- X/*
- X * These routines are written in the calc language. At the time of this
- X * notice, calc was at version 1.24.7 (We refer to calc, as in the C
- X * program, not the Emacs subsystem).
- X *
- X * Calc is available by anonymous ftp from ftp.uu.net (137.39.1.9)
- X * under the directory /pub/calc.
- X *
- X * If you can't get calc any other way, Email a request to my Email
- X * address as shown below.
- X *
- X * Comments, suggestions, bug fixes and questions about these routines
- X * are welcome. Send Email to the address given below.
- X *
- X * Happy bit twiddling,
- X *
- X * Landon Curt Noll
- X *
- X * chongo@toad.com
- X * ...!{pyramid,sun,uunet}!hoptoad!chongo
- X */
- X
- X/*
- X * AN OVERVIEW OF THE FUNCTIONS:
- X *
- X * This calc library contains several pseudo-random number generators:
- X *
- X * additive 55:
- X *
- X * a55rand - external interface to the additive 55 generator
- X * sa55rand - seed the additive 55 generator
- X *
- X * This is a generator based on the additive 55 generator as
- X * described in Knuth's "The Art of Computer Programming -
- X * Seminumerical Algorithms", vol 2, 2nd edition (1981),
- X * Section 3.2.2, page 27, Algorithm A.
- X *
- X * The period and other properties of this generator make it very
- X * useful to 'seed' other generators.
- X *
- X * This generator is used by other other generators to produce
- X * various internal values. In fact, the lower 64 bits of seed
- X * given to other other generators is passed to sa55rand().
- X *
- X * shuffle:
- X *
- X * shufrand - generate a pseudo-random value via a shuffle process
- X * sshufrand - seed the shufrand generator
- X * rand - generate a pseudo-random value over a given range
- X * srand - seed the random stream generator
- X *
- X * This is a generator based on the shuffle generator as described in
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B.
- X *
- X * The shuffle generator is fast and serves as a fairly good standard
- X * pseudo-random generator.
- X *
- X * The shuffle generator is feed random values by the additive 55
- X * generator via a55rand(). Calling a55rand() or sa55rand() will
- X * affect the shuffle generator output.
- X *
- X * The rand function is really another interface to the shuffle
- X * generator. Unlike shufrand(), rand() can return a value of any
- X * given size. The value returned by rand() may be confined to
- X * either a half open [0,a) (0 <= value < a) or closed interval
- X * [a,b] (a <= value <= b). By default, a 64 bit value is returned.
- X *
- X * Calling srand() simply calls sshufrand() with the same seed.
- X *
- X * crypto:
- X *
- X * cryrand - produce a cryptographically strong pseudo-random number
- X * scryrand - seed the crypto generator
- X * random - produce a cryptographically strong pseudo-random number
- X * over a given range
- X * srandom - seed random
- X *
- X * This generator is described in the papers:
- X *
- X * Blum, Blum, and Shub, "Comparison of Two Pseudorandom Number
- X * Generators", in Chaum, D. et. al., "Advances in Cryptology:
- X * Proceedings Crypto 82", pp. 61-79, Plenum Press, 1983.
- X *
- X * "Probabilistic Encryption", Journal of Computer & System
- X * Sciences 28, pp. 270-299.
- X *
- X * We also refer to this generator as the 'Blum' generator.
- X *
- X * This generator is considered 'strong' in that it passes all
- X * polynomial-time statistical tests. This means that there
- X * is no statistical test, which runs in polynomial time, that
- X * can distinguish the crypto generator from a truly random source.
- X *
- X * The crypto generator is not as fast as most generators, though
- X * it is not painfully slow either.
- X *
- X * One may fully seed this generator via scryrand(). Calling
- X * scryrand() with 1 or 3 arguments will result in the additive
- X * 55 generator being seeded with the same seed. Calling
- X * scryrand() with 4 arguments, where the first argument
- X * is >= 0 will also result in the additive 55 generator
- X * being seeded with the same seed.
- X *
- X * The random() generator is really another interface to the
- X * crypto generator. Unlike cryrand(), random() can return a
- X * value confined to either a half open (0 <= value < a) or closed
- X * interval (a <= value <= b). By default, a 64 bit value is
- X * returned.
- X *
- X * Calling srandom() simply calls scryrand(seed). The additive
- X * 55 generator will be seeded with the same seed.
- X *
- X * All generators come already seeded with precomputed initial constants.
- X * Thus, it is not required to seed a generator before using it.
- X *
- X * Using a seed of '0' will reload generators with their initial states.
- X * In the case of scryrand(), lengths of -1 must also be supplied.
- X *
- X * sa55rand(0)
- X * sshufrand(0)
- X * srand(0)
- X * scryrand(0,-1,-1)
- X * srandom(0)
- X * scryrand(-1,ip,iq,ir)
- X *
- X * All of the above 'seed 0' calls are fairly fast. In fact, passing
- X * seeding with a non-zero seed, in the above cases, where seed is
- X * not excessively large (many bits long), is also reasonably fast.
- X * The 4 arg scryrand() call is fairly fast because no checking is
- X * performed on the 'ip', 'iq', or 'ir' values.
- X *
- X * A call of scryrand(seed,len1,len2), with len1,len2 > 4, (3 args)
- X * is a somewhat slow as the length args increase. This type of
- X * call selects 2 primes that are used internally by the crypto
- X * generator. A call of scryrand(seed,ip,iq,ir) where seed >= 0
- X * is as slow as the 3 arg case. See scryrand() for more information.
- X *
- X * A call of scryrand() (no args) may be used to quickly change the
- X * internal state of the crypto and random generators. Only one major
- X * internal crypto generator value (a quadratic residue) is randomly
- X * selected via the additive 55 generator. The other 2 major internal
- X * values (the 2 Blum primes) are preserved. In this form, the additive
- X * 55 is not seeded.
- X *
- X * Calling scryrand() with 1 or 3 args, or calling srandom() will leave
- X * the additive 55 generator in a seeded state as if sa55rand(seed) has
- X * been called. Calling scryrand() with 4 args, where the first arg is
- X * >0 will also leave the additive 55 generator in the same scryrand(seed)
- X * state. Calling scryrand() with no args will not seed the additive
- X * 55 generator before or afterwards, however the additive 55 and shuffle
- X * generators will be changed as a side effect of that call.
- X *
- X * The states of all generators (additive 55, shuffle and crypto) can be
- X * saved and restored via the randstate() function. Saving the state just
- X * after * seeding a generator and restoring it later as a very fast way
- X * to reseed a generator.
- X *
- X * As a bonus, the function 'nxtprime' is provided to produce a probable
- X * prime number.
- X *
- X * TRUTH IN ADVERTISING:
- X *
- X * The word 'probable', in reference to the nxtprime() function, is used
- X * because of an extremely extremely small chance that a composite (a
- X * non-prime) may be returned. In no cases will a prime be skipped.
- X * For our purposes, this is sufficient as the chance of returning a
- X * composite is much smaller than the chance that a hardware glitch
- X * will cause nxtprime() to return a bogus result.
- X *
- X * Another "truth in advertising" issue is the use of the term
- X * 'pseudo-random'. All deterministic generators are pseudo random.
- X * This is opposed to true random generators based on some special
- X * physical device.
- X *
- X * The crypto generator is 'pseudo-random'. There is no statistical
- X * test, which runs in polynomial time, that can distinguish the crypto
- X * generator from a truly random source.
- X *
- X * A final "truth in advertising" issue deals with how the magic numbers
- X * found in this library were generated. Detains can be found in the
- X * various functions, while a overview can be found in the SOURCE FOR
- X * MAGIC NUMBERS section below.
- X *
- X ****
- X *
- X * ON THE GENERATORS:
- X *
- X * The additive 55 generator has a good period, and is fast. It is
- X * reasonable as generators go, though there are better ones available.
- X * We use it in seeding the crypto generator as its period and
- X * other statistical properties are good enough for our purposes.
- X *
- X * This shuffle generator has a very good period, and is fast. It is
- X * fairly good as generators go, and is better than the additive 55
- X * generator. Casual direct use of the shuffle generator may be
- X * acceptable. Because of this, the interface to the shuffle generator,
- X * but not the additive 55 generator, is advertised when this file is
- X * loaded.
- X *
- X * The shuffle generator functions, shufrand() and rand() use the same
- X * seed and tables. The shuffle generator shuffles the values produced
- X * by the additive 55 generator. Calling or seeding the additive 55
- X * generator will affect the output of the shuffle generator.
- X *
- X * The crypto generator is the best generator in this package. It
- X * produces a cryptographically strong pseudo-random bit sequence.
- X * Internally, a fixed number of bits are generated after each
- X * generator iteration. Any unused bits are saved for the next call
- X * to the generator. The crypto generator is not too slow, though
- X * seeding the generator from scratch is slow. Shortcuts and
- X * pre-computer seeds have been provided for this reason. Use of
- X * crypto should be more than acceptable for many applications.
- X *
- X * The crypto seed is in 4 parts, the additive 55 seed (lower 64
- X * bits of seed), the shuffle seed (all but the lower 64 bits of
- X * seed), and two lengths. The two lengths specifies the minimum
- X * bit size of two primes used internal to the crypto generator.
- X * Not specifying the lengths, or using -1 will cause crypto to
- X * use the default minimum lengths of 248 and 264 bits, respectively.
- X *
- X * The random() function just another interface to the crypto
- X * generator. Like rand(), random() provides an interval capability
- X * (closed or open) as well as a 64 bit default return value.
- X * The random() function as good as crypto, and produces numbers
- X * that are equally cryptographically strong. One may use the
- X * seed functions srandom() or scryrand() for either the random()
- X * or cryrand() functions.
- X *
- X * The seed for all of the generators may be of any size. Only the
- X * lower 64 bits of seed affect the additive 55 generator. Bits
- X * beyond the lower 64 bits affect the shuffle generators. Excessively
- X * large values of seed will result in increased memory usage as
- X * well as a larger seed time for the shuffle and crypto generators.
- X * See REGARDING SEEDS below, for more information.
- X *
- X * One may save and restore the state of all generators via the
- X * randstate() function.
- X *
- X ****
- X *
- X * REGARDING SEEDS:
- X *
- X * Because the generators are interrelated, seeding one generator
- X * will directly or indirectly affect the other generators. Seeding
- X * the shuffle generator seeds the additive 55 generator. Seeding
- X * the crypto generator seeds the shuffle generator.
- X *
- X * The seed of '0' implies that a generator should be seeded back
- X * to its initial default state.
- X *
- X * For the moment, seeds < -1 are reserved for future use. The
- X * value of -1 is used as a special indicator to the fourth form
- X * of scryrand(), and it not a real seed.
- X *
- X * A seed may be of any size. The additive 55 generator uses only
- X * the lower 64 bits, while the shuffle generator uses bytes beyond
- X * the lower 64 bits.
- X *
- X * To help make the generator produced by seed S, significantly
- X * different from S+1, seeds are scrambled prior to use. The
- X * function randreseed64() maps [0,2^64) into [0,2^64) in a 1-to-1
- X * and onto fashion.
- X *
- X * The purpose of the randreseed64() is not to add security. It
- X * simply helps remove the human perception of the relationship
- X * between the seed and the production of the generator.
- X *
- X * The randreseed64() process does not reduce the security of the
- X * generators. Every seed is converted into a different unique seed.
- X * No seed is ignored or favored.
- X *
- X * There is no limit on the size of a seed. On the other hand,
- X * extremely large seeds require large tables and long seed times.
- X * Using a seed in the range of [2^64, 2^64 * 128!) should be
- X * sufficient for most purposes. An easy way to stay within this
- X * range to to use seeds that are between 21 and 215 digits, or 64 to
- X * 780 bits long.
- X *
- X ****
- X *
- X * SOURCE OF MAGIC NUMBERS:
- X *
- X * Most of the magic constants used on this library ultimately are
- X * based on the Rand book of random numbers. The Rand book contains
- X * 10^6 decimal digits, generated by a physical process. This book,
- X * produced by the Rand corporation in the 1950's is considered
- X * a standard against which other generators may be measured.
- X *
- X * The Rand book of numbers was groups into groups of 20 digits.
- X * The first 55 groups < 2^64 were used to initialize add55_init_tbl.
- X * The size of 20 digits was used because 2^64 is 20 digits long.
- X * The restriction of < 2^64 was used to prevent modulus biasing.
- X * (see the note on modulus biasing in rand()).
- X *
- X * The additive 55 generator during seeding is used 128 times to help
- X * remove the initial seed state from the initial values produced.
- X * The loop count of 128 was a power of 2 that permits each of the
- X * 55 table entries to be processed at least twice.
- X *
- X * The function, randreseed64(), uses 4 primes to scramble 64 bits
- X * into 64 bits. These primes were also extracted from the Rand
- X * book of numbers. See sshufrand() for details.
- X *
- X * The default shuffle table size of 128 entries is the power of 2
- X * that is longer than the 100 entries recommended by Knuth for
- X * the shuffle algorithm (see the text cited in shufrand()).
- X * We use a power of 2 shuffle table length so that the shuffle
- X * process can select a table entry from a new additive 55 value
- X * by extracting its top most bits.
- X *
- X * The quadratic residue search performed by cryres() starts at
- X * a value that is in the interval [2^sqrpow,n-3), where 2^sqrpow
- X * is the first power of 2 > n^(3/4) and n = p*q. We look at 1009
- X * random numbers in this interval for a quadratic residue. If
- X * none are found, sqrpow is decremented by 1 if sqrpow > 2.
- X * In practice, decrementing sqrpow never happens.
- X *
- X * The use of n^(3/4) insures that the quadratic residue is
- X * large, but not too large. We want to avoid residues that are
- X * near the square root of 'n', and are nearly 'n' itself (hence
- X * the n-3 upper limit) as such residues are trivial or semi-trivial.
- X *
- X * The '1009' trials is simply an attempt to look for a while before
- X * picking a new range. The number '1009' comes from the first 4
- X * digits of the rand book of numbers.
- X *
- X * Keeping sqrpow > 2 means that we do not look for quadratic
- X * residues that are below 4. This is in keeping with the
- X * n-3 in the [2^sqrpow,n-3) interval.
- X *
- X * The final magic numbers: '248' and '264' are the exponents the
- X * largest powers of 2 that are < the two default Blum primes 'p'
- X * and 'q' used by the crypto generator. The values of '248' and
- X * '264' implies that the product n=p*q > 2^512. Each iteration
- X * of the crypto generator produces log2(log2(n=p*q)) random bits.
- X * The crypto generator is the most efficient when n is slightly >
- X * 2^(2^b). The product n > 2^(2^9)) produces 9 bits as efficiently
- X * as possible under the crypto generator process.
- X *
- X * Not being able to factor 'n=p*q' into 'p' and 'q' does not directly
- X * improve the crypto generator. On the other hand, it can't hurt.
- X * The two len values differ slightly to avoid factorization attacks
- X * that work on numbers that are a perfect square, or where the two
- X * primes are nearly the same. I elected to have the sizes differ
- X * by 3% of the product size. The difference between '248' and
- X * '264', is '16', which is ~3.125% of '512'. Now 3% of '512' is
- X * '~15.36', and the next largest whole number is '16'.
- X *
- X * The product n=p*q > 2^512 implies a product if at least 155 digits.
- X * A product of two primes that is at least 155 digits is slightly
- X * beyond Number Theory and computer power of Nov 1992, though this
- X * will likely change in the future.
- X *
- X * Again, the ability (or lack thereof) to factor 'n=p*q' does not
- X * directly relate to the strength of the crypto generator. We
- X * selected n=p*q > 2^512 mainly because '512 was a power of 2 and
- X * only slightly because it is up in the range where it is difficult
- X * to factor.
- X *
- X ****
- X *
- X * FOR THE PARANOID:
- X *
- X * The truly paranoid might suggest that my claims in the MAGIC NUMBERS
- X * section are a lie intended to entrap people. Well they are not, but
- X * you need not take my word for it.
- X *
- X * The random numbers from the Rand book of random numbers can be
- X * verified by anyone who obtains the book. As these numbers were
- X * created before I (Landon Curt Noll) was born (you can look up
- X * my birth record if you want), I claim to have no possible influence
- X * on their generation.
- X *
- X * There is a very slight chance that the electronic copy of the
- X * Rand book that I was given access to differs from the printed text.
- X * I am willing to provide access to this electronic copy should
- X * anyone wants to compare it to the printed text.
- X *
- X * One might object to the complexity of the seed scramble/mapping
- X * via the randreseed64() function. The randreseed64() function maps:
- X *
- X * 1 ==> 4967126403401436567
- X *
- X * calling srand(1) with the randreseed64() process would be the same
- X * as calling srand(4967126403401436567) without it. No extra security
- X * is gained or reduced by using the randreseed64() process. The meaning
- X * of seeds are exchanged, but not lost or favored (used by more than
- X * one input seed).
- X *
- X * One could take issue with my selection of the default sizes '248'
- X * and '264'. As far as I know, 155 digits (512 bits) is beyond the
- X * state of the art of Number Theory and Computation as of 01 Sep 92.
- X * It will likely be true that 155 digit products of two primes could
- X * come within reach in the next few years, but so what? If you are
- X * truly paranoid, why would you want to use the default seed, which
- X * is well known?
- X *
- X * The paranoid today might consider using the lengths of at least '345'
- X * and '325' will produce a product of two primes that is 202 digits.
- X * (the 2nd and 3rd args of scryrand > 345 & >325 respectively) Factoring
- X * 200+ digit product of two primes is well beyond the current hopes of
- X * Number Theory and Computer power, though even this limit may be passed
- X * someday.
- X *
- X * If all the above fails to pacify the truly paranoid, then one may
- X * select by some independent means, 2 Blum primes (primes mod 4 == 3,
- X * p < q), and a quadratic residue if p*q. Then by calling:
- X *
- X * scryrand(-1, p, q, r)
- X *
- X * and then calling cryrand() or random(), one may bypass all magic
- X * numbers and use the pure generator.
- X *
- X * Note that randstate() may also be used by the truly paranoid.
- X * Even though it holds state for the other generators, their states
- X * are independent.
- X *
- X ****
- X *
- X * GOALS:
- X *
- X * The goals of this package are:
- X *
- X * all magic numbers are explained
- X *
- X * I distrust systems with constants (magic numbers) and tables
- X * that have no justification (e.g., DES). I believe that I have
- X * done my best to justify all of the magic numbers used.
- X *
- X * full documentation
- X *
- X * You have this source file, plus background publications,
- X * what more could you ask?
- X *
- X * large selection of seeds
- X *
- X * Seeds are not limited to a small number of bits. A seed
- X * may be of any size.
- X *
- X * the strength of the generators may be tuned to meet the application need
- X *
- X * By using the appropriate seed arguments, one may increase
- X * the strength of the generator to suit the need of the
- X * application. One does not have just a few levels.
- X *
- X * This calc lib file is intended for demonstration purposes. Writing
- X * a C program (with possible assembly or libmp assist) would produce
- X * a faster generator.
- X *
- X * Even though I have done my best to implement a good system, you still
- X * must use these routines your own risk.
- X *
- X * Share and enjoy! :-)
- X */
- X
- X
- X/*
- X * These constants are used by all of the generators in various direct and
- X * indirect forms.
- X */
- Xstatic cry_seed = 0; /* master seed */
- Xstatic cry_mask = 0xffffffffffffffff; /* 64 bit work mask */
- X
- X
- X/*
- X * Initial magic values for the additive 55 generator - used by sa55rand()
- X *
- X * These values were generated from the Rand book of random numbers.
- X * In groups of 20 digits, we took the first 55 groups < 2^64.
- X */
- Xstatic mat add55_init_tbl[55] = {
- X 10097325337652013586, 8422689531964509303,
- X 9376707153831131165, 12807999708015736147,
- X 12171768336606574717, 2051656926866574818,
- X 3529647783580834282, 13746700781847540610,
- X 17468509505804776974, 14385537637435099817,
- X 14225685144642756788, 11100020401286074697,
- X 7207317906119690446, 15474452669527079953,
- X 16868487670307112059, 4493524947524633824,
- X 13021248927856520106, 15956600001874392423,
- X 1758753794041921585, 1540354560501451176,
- X 5335129695612719255, 9973334408846123356,
- X 2295368703230757546, 15020099946907494138,
- X 10518216150184876938, 9188200973282539527,
- X 4220863048338987374, 682273982071453295,
- X 7706178130835869910, 4618975533122308420,
- X 397583911260717646, 5686731560708285046,
- X 10123916228549657560, 1304775865627110086,
- X 15501295782182641134, 3061180729620744156,
- X 6958929830512809719, 10850627469959910507,
- X 13499063195307571839, 6410193623982098952,
- X 4111084083850807341, 17719042079595449953,
- X 5462692006544395659, 18288274374963224041,
- X 8337656769629990836, 7477446061798548911,
- X 9815931464890815877, 6913451974267278601,
- X 11883095286301198901, 14974403441045516019,
- X 14210337129134237821, 12883973436502761184,
- X 4285013921797415077, 16435915296724552670,
- X 3742838738308012451
- X};
- X
- X
- X/*
- X * additive 55 tables - used by a55rand() and sa55rand()
- X */
- Xstatic add55_j = 23; /* the first walking table pointer */
- Xstatic add55_k = 54; /* the second walking table pointer */
- Xstatic add55_seed64 = 0; /* lower 64 bits of the reseeded seed */
- Xstatic mat add55_tbl[55]; /* additive 55 state table */
- X
- X
- X/*
- X * cryobj - cryptographic pseudo-random state object
- X */
- Xobj cryobj { \
- X p, /* first Blum prime (prime 3 mod 4) */ \
- X q, /* second Blum prime (prime 3 mod 4) */ \
- X r, /* quadratic residue of n=p*q */ \
- X exp, /* used in computing crypto good bits */ \
- X left, /* bits unused from the last cryrand() call */ \
- X bitcnt, /* left contains bitcnt crypto good bits */ \
- X a55j, /* 1st additive 55 table pointer */ \
- X a55k, /* 2nd additive 55 table pointer */ \
- X seed, /* last seed set by sa55rand() or 0 */ \
- X shufy, /* Y (previous a55rand output for shuffle) */ \
- X shufsz, /* size of the shuffle table */ \
- X shuftbl, /* a matrix of shufsz entries */ \
- X a55tbl /* additive 55 generator state table */ \
- X}
- X
- X
- X/*
- X * initial cryptographic pseudo-random values - used by scryrand()
- X *
- X * These values are what the crypto generator is initialized with
- X * with this library first read. These values may be reproduced the
- X * hard way by calling scryrand(0,248,264) or scryrand(0,-1,-1).
- X *
- X * We will build up these values a piece at a time to avoid long lines
- X * that are difficult to send via Email.
- X */
- X/* p, first Blum prime */
- Xstatic cryrand_init_p = 0x1aa9e726a735044;
- Xcryrand_init_p <<= 200;
- Xcryrand_init_p |= 0x73b7457c5297122310880fcbfa8d4e38380a00396d533300bb;
- X/* q, second Blum prime */
- Xstatic cryrand_init_q = 0xa62ee0481aa12059c3;
- Xcryrand_init_q <<= 200;
- Xcryrand_init_q |= 0x79ef44e72ff58ea70cacabbe9d264a0b16db72117d96f77e17;
- X/* quadratic residue of n=p*q */
- Xstatic cryrand_init_r = 0x3d214853f9a5bb4b12f467c9052129a9;
- Xcryrand_init_r <<= 200;
- Xcryrand_init_r |= 0xd215cc6b3c2eae8c7090591b16d8044a886b3c6a58759b1a07;
- Xcryrand_init_r <<= 200;
- Xcryrand_init_r |= 0x2b50a914b42e1b6f9703be86742837c4bc637804c2dc668c5b;
- X
- X/*
- X * cryptographic pseudo-random values - used by cryrand() and scryrand()
- X */
- X/* p, first Blum prime */
- Xstatic cryrand_p = cryrand_init_p;
- X/* q, second Blum prime */
- Xstatic cryrand_q = cryrand_init_q;
- X/* n = p*q */
- Xstatic cryrand_n = cryrand_p*cryrand_q;
- X/* quad residue of n */
- Xstatic cryrand_r = cryrand_init_r;
- X/* this cryrand() running exp used in computing crypto good bits */
- Xstatic cryrand_exp = cryrand_r;
- X/* good crypto bits unused from the last cryrand() call */
- Xstatic cryrand_left = 0;
- X/* the value cryrand_left contains cryrand_bitcnt crypto good bits */
- Xstatic cryrand_bitcnt = 0;
- X
- X
- X/*
- X * shufrand - shuffle generator constants
- X */
- Xstatic shuf_size = 128; /* entries in shuffle table */
- Xstatic shuf_shift = (64-highbit(shuf_size)); /* shift a55 value to get tbl indx */
- Xstatic shuf_y; /* Y value (previous output) */
- Xstatic mat shuf_tbl[shuf_size]; /* shuffle state table */
- X
- X
- X/*
- X * products of consecutive primes - used by nxtprime()
- X *
- X * We compute these products now to avoid recalculating them on each call.
- X * These values help weed out numbers that have a prime factor < 1000.
- X */
- Xstatic nxtprime_pfact10 = pfact(10);
- Xstatic nxtprime_pfact100 = pfact(100)/nxtprime_pfact10;
- Xstatic nxtprime_pfact1000 = pfact(1000)/nxtprime_pfact100;
- X
- X
- X/*
- X * a55rand - additive 55 pseudo-random number generator
- X *
- X * returns:
- X * A number in the half open interval [0,2^64)
- X *
- X * This function implements the additive 55 pseudo-random number generator.
- X *
- X * This is a generator based on the additive 55 generator as described in
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.2.2, page 27, Algorithm A.
- X *
- X * This function is called from the shuffle generator function shufrand().
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you are looking for a fast generator and do not need a crypto
- X * strong generator, you should not use this generator. Use of
- X * the shuffle generator functions shufrand() and rand() should
- X * be considered instead.
- X */
- Xdefine
- Xa55rand()
- X{
- X local ret; /* the pseudo-random number to return */
- X
- X /* generate the next value using the additive 55 generator method */
- X ret = add55_tbl[add55_k] + add55_tbl[add55_j];
- X ret &= cry_mask;
- X add55_tbl[add55_k] = ret;
- X
- X /* post-process out data with the seed */
- X ret = xor(ret, add55_seed64);
- X
- X /* step the pointers */
- X --add55_j;
- X if (add55_j < 0) {
- X add55_j = 54;
- X }
- X --add55_k;
- X if (add55_k < 0) {
- X add55_k = 54;
- X }
- X
- X /* return the new pseudo-random number */
- X return(ret);
- X}
- X
- X
- X/*
- X * sa55rand - initialize the additive 55 pseudo-random generator
- X *
- X * given:
- X * seed
- X *
- X * returns:
- X * old_seed
- X *
- X * This function seeds the additive 55 pseudo-random generator.
- X *
- X * This is a generator based on the additive 55 generator as described in
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.2.2, page 27, Algorithm A.
- X *
- X * Unlike Knuth's description, we will let a seed post process our data.
- X *
- X * We do not apply the seed processing to the additive 55 table
- X * data as this would disturb its pseudo-random generator properties.
- X * Instead, we xor the output with the low 64 bits of seed.
- X *
- X * If seed == 0:
- X *
- X * This function produces values in exactly the same way
- X * described by Knuth.
- X *
- X * else:
- X *
- X * Each value produced is xor-ed by a 64 bit value. This value
- X * is the result of randreseed64(rand), which produces a 64
- X * bit value.
- X *
- X * Anyone comfortable with seed == 0 should also be comfortable with
- X * non-zero seeds. A non-zero seeded sequence will produce a values
- X * that have the exact same pseudo-random properties as the algorithm
- X * described by Knuth. I.e., the sequence, while different, is as good
- X * (or bad) as the sequence produced by a seed of 0.
- X *
- X * This function updates both the cry_seed and a55_seed64 global values.
- X *
- X * This function is called from the shuffle generator seed function sshufrand().
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you are looking for a fast generator and do not need a crypto
- X * strong generator, you should not use this generator. Use of the
- X * shuffle generator seed functions sshufrand() and srand() should
- X * be considered instead.
- X */
- Xdefine
- Xsa55rand(seed)
- X{
- X local oldseed; /* previous seed */
- X local junk; /* discards the first few numbers */
- X local j;
- X
- X /* firewall */
- X if (!isint(seed)) {
- X quit "bad arg: arg must be an integer";
- X }
- X if (seed < 0) {
- X quit "bad arg: seed < 0 is reserved for future use";
- X }
- X
- X /* misc table setup */
- X oldseed = cry_seed; /* remember the previous seed */
- X cry_seed = seed; /* save the new seed */
- X add55_tbl = add55_init_tbl; /* reload the table */
- X add55_j = 23; /* reset first walking table pointer */
- X add55_k = 54; /* reset second walking table pointer */
- X
- X /* obtain our 64 bit xor seed */
- X add55_seed64 = randreseed64(seed);
- X
- X /* spin the pseudo-random number generator a while */
- X for (j=0; j < 128; ++j) {
- X junk = a55rand();
- X }
- X
- X /* return the old seed */
- X return(oldseed);
- X}
- X
- X
- X/*
- X * shufrand - implement the shuffle pseudo-random number generator
- X *
- X * returns:
- X * A number in the half open interval [0,2^64)
- X *
- X * This function implements the shuffle number generator.
- X *
- X * This is a generator based on the shuffle generator as described in
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B.
- X *
- X * The function rand() calls this function.
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you do not need a crypto strong pseudo-random generator
- X * this function may very well serve your needs.
- X */
- Xdefine
- Xshufrand()
- X{
- X local j; /* table index to replace */
- X
- X /*
- X * obtain a new random value
- X * determine the table entry to shuffle
- X * shuffle out the value we will return
- X */
- X shuf_y = shuf_tbl[j = (shuf_y >> shuf_shift)];
- X
- X /* shuffle in the new random value */
- X shuf_tbl[j] = a55rand();
- X
- X /* return the shuffled out value */
- X return (shuf_y);
- X}
- X
- X
- X/*
- X * sshufrand - seed the shuffle pseudo-random generator
- X *
- X * given:
- X * a seed
- X *
- X * returns:
- X * the previous seed
- X *
- X * This function implements the shuffle number generator.
- X *
- X * This is a generator based on the shuffle generator as described in
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.2.2, page 32, Algorithm B.
- X *
- X * The low 64 bits of seed are used by the additive 55 generator.
- X * See the sa55rand() function for details. The remaining bits of seed
- X * are used to perform an initial shuffle on the shuffle state table.
- X * The size of the seed also determines the size of the shuffle table.
- X *
- X * The shuffle table size is always a power of 2, and is at least 128
- X * entries long. Let the table size be:
- X *
- X * shuf_size = 2^shuf_pow
- X *
- X * The number of ways one could shuffle that table is:
- X *
- X * (2^shuf_pow)!
- X *
- X * We select the smallest 'shuf_pow' (and thus the size of the shuffle table)
- X * such that the following are true:
- X *
- X * (2^shuf_pow)! >= (seed / 2^64) and 2^shuf_pow >= 128
- X *
- X * Given that we now have the table size of 'shuf_size', we must go about
- X * loading the table and shuffling it.
- X *
- X * Loading is easy, we will generate random values via the additive 55
- X * generator (a55rand()) and load them into successive entries.
- X *
- X * We enumerate the (2^shuf_pow)! values via:
- X *
- X * shuf_seed = 2*(U[2] + 3*(U[3] + 4*(U[4] + ...
- X * + (U[shuf_pow-1]*(shuf_pow-1)) ... )))
- X * 0 <= U[j] < j
- X *
- X * We swap the swap table entries shuf_tbl[U[j]] & shuf_tbl[j-1] for all
- X * 1 < j < shuf_pow.
- X *
- X * We will convert 'seed / 2^64' into shuf_seed, by applying the 64 bit
- X * scramble function on 64 bit chunks of 'seed / 2^64'.
- X *
- X * The function srand() calls this function.
- X *
- X * There is no limit on the size of a seed. On the other hand,
- X * extremely large seeds require large tables and long seed times.
- X * Using a seed in the range of [2^64, 2^64 * 128!) should be
- X * sufficient for most purposes. An easy way to stay within this
- X * range to to use seeds that are between 21 and 215 digits long, or
- X * 64 to 780 bits long.
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you do not need a crypto strong pseudo-random generator
- X * this function may very well serve your needs.
- X */
- Xdefine
- Xsshufrand(seed)
- X{
- X local shuf_pow; /* power of two - log2(shuf_size) */
- X local shuf_seed; /* seed bits beyond low 64 bits */
- X local oldseed; /* previous seed */
- X local shift; /* shift factor to access 64 bit chunks */
- X local swap_indx; /* what to swap shuf_tbl[0] with */
- X local rval; /* random value form additive 55 generator */
- X local j;
- X
- X /* firewall */
- X if (!isint(seed)) {
- X quit "bad arg: seed must be an integer";
- X }
- X if (seed < 0) {
- X quit "bad arg: seed < 0 is reserved for future use";
- X }
- X
- X /*
- X * seed the additive 55 generator
- X */
- X oldseed = sa55rand(seed);
- X
- X /*
- X * form the shuffle table size and constants
- X */
- X shuf_seed = seed >> 64;
- X for (shuf_pow = 7; shuf_seed > (j=fact(1<<(shuf_pow))) && shuf_pow < 64; \
- X ++shuf_pow) {
- X }
- X shuf_size = (1 << shuf_pow);
- X shuf_shift = 64 - shuf_pow;
- X /* reallocate the shuffle table */
- X mat shuf_tbl[shuf_size];
- X
- X /*
- X * scramble the seed above the low 64 bits
- X */
- X if (shuf_seed > 0) {
- X j = 0;
- X for (shift=0; shift < highbit(shuf_seed)+1; shift += 64) {
- X j |= (randreseed64(shuf_seed >> shift) << shift);
- X }
- X shuf_seed = j;
- X }
- X
- X /*
- X * load the shuffle table
- X */
- X for (j=0; j < shuf_size; ++j) {
- X shuf_tbl[j] = a55rand();
- X }
- X shuf_y = a55rand(); /* get the next Y value */
- X
- X /*
- X * We will shuffle based the process outlined in:
- X *
- X * Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
- X * vol 2, 2nd edition (1981), Section 3.4.2, page 139, Algorithm P.
- X *
- X * Here, we will let j run over the range [0,shuf_size) instead of
- X * [shuf_size,0) as outlined in algorithm P. We will also generate
- X * U values from shuf_seed.
- X */
- X j = 0;
- X while (shuf_seed > 0 && ++j < shuf_size) {
- X
- X /* determine what index we will swap with the '0' index */
- X quomod(shuf_seed, (j+1), shuf_seed, swap_indx);
- X
- X /* swap table entries, if needed */
- X if (swap_indx != j) {
- X swap(shuf_tbl[j], shuf_tbl[swap_indx]);
- X }
- X }
- X
- X /*
- X * run the generator for twice the table size
- X */
- X for (j=0; j < shuf_size*2; ++j) {
- X rval = shufrand();
- X }
- X
- X /* return the old seed */
- X return (oldseed);
- X}
- X
- X
- X/*
- X * rand - generate a pseudo-random value over a given range via additive 55
- X *
- X * usage:
- X * rand() - generate a pseudo-random integer >=0 and < 2^64
- X * rand(a) - generate a pseudo-random integer >=0 and < a
- X * rand(a,b) - generate a pseudo-random integer >=a and <= b
- X *
- X * returns:
- X * a large pseudo-random integer over a give range (see usage)
- X *
- X * When no arguments are given, a pseudo-random number in the half open
- X * interval [0,2^64) is produced. This form is identical to calling
- X * shufrand().
- X *
- X * When 1 argument is given, a pseudo-random number in the half open interval
- X * [0,a) is produced.
- X *
- X * When 2 arguments are given, a pseudo-random number in the closed interval
- X * [a,b] is produced.
- X *
- X * The input values a and b, if given, must be integers.
- X *
- X * This generator is simply a different interface to the shuffle generator.
- X * calling shufrand(), or seeding via sshufrand() will affect the output
- X * of this function.
- X *
- X * NOTE: Unlike cryrand(), this function does not preserve unused bits for
- X * use by the next function call.
- X *
- X * NOTE: The Un*x rand() function returns only 16 bit or 31 bits, while we
- X * return a number of any given size (default is 64 bits).
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you do not need a crypto strong pseudo-random generator
- X * this function may very well serve your needs.
- X */
- Xdefine
- Xrand(a,b)
- X{
- X local range; /* we must generate [0,range) first */
- X local offset; /* what to add to get a adjusted range */
- X local ret; /* pseudo-random value */
- X local fullwords; /* number of full 64 bit chunks in ret */
- X local finalmask; /* mask of bits in final chunk of range */
- X local j;
- X
- X /*
- X * setup and special cases
- X */
- X /* deal with the rand() case */
- X if (isnull(a) && isnull(b)) {
- X /* no args means same range as additive 55 generator */
- X return(a55rand());
- X }
- X /* firewall - args, if given must be in integers */
- X if (!isint(a) || (!isnull(b) && !isint(b))) {
- X quit "bad args: args, if given, must be integers";
- X }
- X /* convert rand(x) into rand(0,x-1) */
- X if (isnull(b)) {
- X /* convert call into a closed interval */
- X b = a-1;
- X a = 0;
- X /* firewall - rand(0) should act like rand(0,0) */
- X if (b == -1) {
- X return(0);
- X }
- X }
- X /* determine the range and offset */
- X if (a >= b) {
- X /* deal with the case of rand(a,a) */
- X if (a == b) {
- X /* not very random, but it is true! */
- X return(a);
- X }
- X range = a-b+1;
- X offset = b;
- X } else {
- X /* convert rand(a,b), where a < b into rand(b,a) */
- X range = b-a+1;
- X offset = a;
- X }
- X /*
- X * At this point, we seek a pseudo-random number [0,range) to which
- X * we will add offset to produce a number [offset,range+offset).
- X */
- X fullwords = highbit(range-1)//64;
- X finalmask = (1 << (1+(highbit(range-1)%64)))-1;
- X
- X /*
- X * loop until we get a value that is in range
- X *
- X * A note in modulus biasing:
- X *
- X * We will not fall into the trap of thinking that we can simply take
- X * a value mod 'range'. Consider the case where 'range' is '80'
- X * and we are given pseudo-random numbers [0,100). If we took them
- X * mod 80, then the numbers [0,20) would be produced more frequently
- X * because the numbers [81,100) mod 80 wrap back into [0,20).
- X */
- X do {
- X /* load up all lower full 64 bit chunks with pseudo-random bits */
- X ret = 0;
- X for (j=0; j < fullwords; ++j) {
- X ret = (ret << 64) + shufrand();
- X }
- X
- X /* load the highest chunk */
- X ret <<= (highbit(finalmask)+1);
- X ret |= (shufrand() >> (64-highbit(finalmask)-1));
- X } while (ret >= range);
- X
- X /*
- X * return the adjusted range value
- X */
- X return(ret+offset);
- X}
- X
- X
- X/*
- X * srand - seed the pseudo-random additive 55 generator
- X *
- X * input:
- X * seed
- X *
- X * returns:
- X * old_seed
- X *
- X * This function actually seeds the shuffle generator (and indirectly
- X * the additive 55 generator used by rand() and a55rand().
- X *
- X * See sshufrand() and sa55rand() for information about a seed.
- X *
- X * There is no limit on the size of a seed. On the other hand,
- X * extremely large seeds require large tables and long seed times.
- X * Using a seed in the range of [2^64, 2^64 * 128!) should be
- X * sufficient for most purposes. An easy way to stay within this
- X * range to to use seeds that are between 21 and 215 digits long, or
- X * 64 to 780 bits long.
- X *
- X * NOTE: This is NOT Blum's method. This is used by Blum's method to
- X * generate some internal values.
- X *
- X * NOTE: If you do not need a crypto strong pseudo-random generator
- X * this function may very well serve your needs.
- X */
- Xdefine
- Xsrand(seed)
- X{
- X if (!isint(seed)) {
- X quit "bad arg: seed must be an integer";
- X }
- X if (seed < 0) {
- X quit "bad arg: seed < 0 is reserved for future use";
- X }
- X return(sshufrand(seed));
- X}
- X
- X
- X/*
- X * cryrand - cryptographically strong pseudo-random number generator
- X *
- X * usage:
- X * cryrand(len)
- X *
- X * given:
- X * len number of pseudo-random bits to generate
- X *
- X * returns:
- X * a cryptographically strong pseudo-random number of len bits
- X *
- X * Internally, bits are produced log2(log2(n=p*q)) at a time. If a
- X * call to this function does not exhaust all of the collected bits,
- X * the unused bits will be saved away and used at a later call.
- X * Setting the seed via scryrand() or srandom() will clear out all
- X * unused bits. Thus:
- X *
- X * scryrand(0); <-- restore generator to initial state
- X * cryrand(16); <-- 16 bits
- X *
- X * will produce the same value as:
- X *
- X * scryrand(0); <-- restore generator to initial state
- X * cryrand(4)<<12 | cryrand(12); <-- 4+12 = 16 bits
- X *
- X * and will produce the same value as:
- X *
- X * scryrand(0); <-- restore generator to initial state
- X * cryrand(3)<<13 | cryrand(7)<<6 | cryrand(6); <-- 3+7+6 = 16 bits
- X *
- X * The crypto generator is not as fast as most generators, though it is not
- X * painfully slow either.
- X *
- X * NOTE: This function is the Blum cryptographically strong
- X * pseudo-random number generator!
- X */
- Xdefine
- Xcryrand(len)
- X{
- X local goodbits; /* the number of good bits generated each pass */
- X local goodmask; /* mask for the low order good bits */
- X local randval; /* pseudo-random value being generated */
- X
- X /*
- X * firewall
- X */
- X if (!isint(len) || len < 1) {
- X quit "bad arg: len must be an integer > 0";
- X }
- X
- X /*
- X * Determine how many bits may be generated each pass.
- X *
- X * The result by Alexi et. al., says that the log2(log2(n=p*q))
- X * least significant bits are secure, where log2(x) is log base 2.
- X */
- X goodbits = highbit(highbit(cryrand_n));
- X goodmask = (1 << goodbits)-1;
- X
- X /*
- X * If we have bits left over from the previous call, collect
- X * them now.
- X */
- X if (cryrand_bitcnt > 0) {
- X
- X /* case where the left over bits are enough for this call */
- X if (len <= cryrand_bitcnt) {
- X
- X /* we need only len bits */
- X randval = (cryrand_left >> (cryrand_bitcnt-len));
- X
- X /* save the unused bits for later use */
- X cryrand_left &= ((1 << (cryrand_bitcnt-len))-1);
- X
- X /* save away the number of bits that we will not use */
- X cryrand_bitcnt -= len;
- X
- X /* return our complete result */
- X return(randval);
- X
- X /* case where we need more than just the left over bits */
- X } else {
- X
- X /* clear out the number of left over bits */
- X len -= cryrand_bitcnt;
- X cryrand_bitcnt = 0;
- X
- X /* collect all of the left over bits for now */
- X randval = cryrand_left;
- X }
- X
- X /* case where we have no previously left over bits */
- X } else {
- X randval = 0;
- X }
- X
- X /*
- X * Pump out len cryptographically strong pseudo-random bits,
- X * 'goodbits' at a time using Blum's process.
- X */
- X while (len >= goodbits) {
- X
- X /* generate the bits */
- X cryrand_exp = (cryrand_exp^2) % cryrand_n;
- X randval <<= goodbits;
- X randval |= (cryrand_exp & goodmask);
- X
- X /* reduce the need count */
- X len -= goodbits;
- X }
- X
- X /* if needed, save the unused bits for later use */
- X if (len > 0) {
- X
- X /* generate the bits */
- X cryrand_exp = (cryrand_exp^2) % cryrand_n;
- X randval <<= len;
- X randval |= ((cryrand_exp&goodmask) >> (goodbits-len));
- X
- X /* save away the number of bits that we will not use */
- X cryrand_left = cryrand_exp & ((1 << (goodbits-len))-1);
- X cryrand_bitcnt = goodbits-len;
- X }
- X
- X /*
- X * return our pseudo-random bits
- X */
- X return(randval);
- X}
- X
- X
- X/*
- X * scryrand - seed the cryptographically strong pseudo-random number generator
- X *
- X * usage:
- X * scryrand(seed)
- X * scryrand()
- X * scryrand(seed,len1,len2)
- X * scryrand(seed,ip,iq,ir)
- X *
- X * input:
- X * [seed pseudo-random seed
- X * [len1 len2] minimum bit length of the Blum primes 'p' and 'q'
- X * -1 => default lengths
- X * [ip iq ir] Initial search values for Blum primes 'p', 'q' and
- X * a quadratic residue 'r'
- X *
- X * returns:
- X * the previous seed
- X *
- X *
- X * This function will seed and setup the generator needed to produce
- X * cryptographically strong pseudo-random numbers. See the function
- X * a55rand() and sshufrand() for information about how 'seed' works.
- X *
- X * The first form of this function are fairly fast if the seed is not
- X * excessively large. The second form is also fairly fast if the internal
- X * primes are not too large. The third form, can take a long time to call.
- X * (see below) The fourth form, if the 'seed' arg is not -1, can take
- X * as long as the third form to call. If the fourth form is called with
- X * a 'seed' arg of -1, then it is fairly fast.
- X *
- X * Calling scryrand() with 1 or 3 args (first and third forms), or
- X * calling srandom(), or calling scryrand() with 4 args with the first
- X * arg >0, will leave the shuffle generator in a seeded state as if
- X * sshufrand(seed) has been called.
- X *
- X * Calling scryrand() with no args will not seed the shuffle generator,
- X * before or afterwards, however the shuffle generator will have been
- X * changed as a side effect of that call.
- X *
- X * Calling scryrand() with 4 args where the first arg is 0 or '-1'
- X * will not change the other generators.
- X *
- X *
- X * First form of call: scryrand(seed)
- X *
- X * The first form of this function will seed the shuffle generator
- X * (via srand). The default precomputed constants will be used.
- X *
- X *
- X * Second form of call: scryrand()
- X *
- X * Only a new quadratic residue of n=p*q is recomputed. The previous prime
- SHAR_EOF
- echo "End of part 16"
- echo "File calc2.9.0/lib/cryrand.cal is continued in part 17"
- echo "17" > s2_seq_.tmp
- exit 0
-