mirror of https://github.com/macssh/macssh.git
361 lines
9.3 KiB
C
361 lines
9.3 KiB
C
|
/* _gmp_rand (rp, state, nbits) -- Generate a random bitstream of
|
||
|
length NBITS in RP. RP must have enough space allocated to hold
|
||
|
NBITS.
|
||
|
|
||
|
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||
|
|
||
|
This file is part of the GNU MP Library.
|
||
|
|
||
|
The GNU MP Library is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU Lesser General Public License as published by
|
||
|
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||
|
option) any later version.
|
||
|
|
||
|
The GNU MP Library is distributed in the hope that it will be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||
|
License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public License
|
||
|
along with the GNU MP Library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||
|
MA 02111-1307, USA. */
|
||
|
|
||
|
#include "gmp.h"
|
||
|
#include "gmp-impl.h"
|
||
|
#include "longlong.h"
|
||
|
|
||
|
/* For linear congruential (LC), we use one of algorithms (1) or (2).
|
||
|
(gmp-3.0 uses algorithm (1) with 'm' as a power of 2.)
|
||
|
|
||
|
LC algorithm (1).
|
||
|
|
||
|
X = (aX + c) mod m
|
||
|
|
||
|
[D. Knuth, "The Art of Computer Programming: Volume 2, Seminumerical Algorithms",
|
||
|
Third Edition, Addison Wesley, 1998, pp. 184-185.]
|
||
|
|
||
|
X is the seed and the result
|
||
|
a is chosen so that
|
||
|
a mod 8 = 5 [3.2.1.2] and [3.2.1.3]
|
||
|
.01m < a < .99m
|
||
|
its binary or decimal digits is not a simple, regular pattern
|
||
|
it has no large quotients when Euclid's algorithm is used to find
|
||
|
gcd(a, m) [3.3.3]
|
||
|
it passes the spectral test [3.3.4]
|
||
|
it passes several tests of [3.3.2]
|
||
|
c has no factor in common with m (c=1 or c=a can be good)
|
||
|
m is large (2^30)
|
||
|
is a power of 2 [3.2.1.1]
|
||
|
|
||
|
The least significant digits of the generated number are not very
|
||
|
random. It should be regarded as a random fraction X/m. To get a
|
||
|
random integer between 0 and n-1, multiply X/m by n and truncate.
|
||
|
(Don't use X/n [ex 3.4.1-3])
|
||
|
|
||
|
The ``accuracy'' in t dimensions is one part in ``the t'th root of m'' [3.3.4].
|
||
|
|
||
|
Don't generate more than about m/1000 numbers without changing a, c, or m.
|
||
|
|
||
|
The sequence length depends on chosen a,c,m.
|
||
|
|
||
|
|
||
|
LC algorithm (2).
|
||
|
|
||
|
X = a * (X mod q) - r * (long) (X/q)
|
||
|
if X<0 then X+=m
|
||
|
|
||
|
[Knuth, pp. 185-186.]
|
||
|
|
||
|
X is the seed and the result
|
||
|
as a seed is nonzero and less than m
|
||
|
a is a primitive root of m (which means that a^2 <= m)
|
||
|
q is (long) m / a
|
||
|
r is m mod a
|
||
|
m is a prime number near the largest easily computed integer
|
||
|
|
||
|
which gives
|
||
|
|
||
|
X = a * (X % ((long) m / a)) -
|
||
|
(M % a) * ((long) (X / ((long) m / a)))
|
||
|
|
||
|
Since m is prime, the least-significant bits of X are just as random as
|
||
|
the most-significant bits. */
|
||
|
|
||
|
/* Blum, Blum, and Shub.
|
||
|
|
||
|
[Bruce Schneier, "Applied Cryptography", Second Edition, John Wiley
|
||
|
& Sons, Inc., 1996, pp. 417-418.]
|
||
|
|
||
|
"Find two large prime numbers, p and q, which are congruent to 3
|
||
|
modulo 4. The product of those numbers, n, is a blum integer.
|
||
|
Choose another random integer, x, which is relatively prime to n.
|
||
|
Compute
|
||
|
x[0] = x^2 mod n
|
||
|
That's the seed for the generator."
|
||
|
|
||
|
To generate a random bit, compute
|
||
|
x[i] = x[i-1]^2 mod n
|
||
|
The least significant bit of x[i] is the one we want.
|
||
|
|
||
|
We can use more than one bit from x[i], namely the
|
||
|
log2(bitlength of x[i])
|
||
|
least significant bits of x[i].
|
||
|
|
||
|
So, for a 32-bit seed we get 5 bits per computation.
|
||
|
|
||
|
The non-predictability of this generator is based on the difficulty
|
||
|
of factoring n.
|
||
|
*/
|
||
|
|
||
|
/* -------------------------------------------------- */
|
||
|
|
||
|
/* lc (rp, state) -- Generate next number in LC sequence. Return the
|
||
|
number of valid bits in the result. NOTE: If 'm' is a power of 2
|
||
|
(m2exp != 0), discard the lower half of the result. */
|
||
|
|
||
|
static
|
||
|
unsigned long int
|
||
|
#if __STDC__
|
||
|
lc (mp_ptr rp, gmp_randstate_t rstate)
|
||
|
#else
|
||
|
lc (rp, rstate)
|
||
|
mp_ptr rp;
|
||
|
gmp_randstate_t rstate;
|
||
|
#endif
|
||
|
{
|
||
|
mp_ptr tp, seedp, ap;
|
||
|
mp_size_t ta;
|
||
|
mp_size_t tn, seedn, an;
|
||
|
mp_size_t retval;
|
||
|
int shiftcount = 0;
|
||
|
unsigned long int m2exp;
|
||
|
mp_limb_t c;
|
||
|
TMP_DECL (mark);
|
||
|
|
||
|
m2exp = rstate->algdata.lc->m2exp;
|
||
|
c = (mp_limb_t) rstate->algdata.lc->c;
|
||
|
|
||
|
seedp = PTR (rstate->seed);
|
||
|
seedn = SIZ (rstate->seed);
|
||
|
|
||
|
if (seedn == 0)
|
||
|
{
|
||
|
/* Seed is 0. Result is C % M. */
|
||
|
*rp = c;
|
||
|
|
||
|
if (m2exp != 0)
|
||
|
{
|
||
|
/* M is a power of 2. */
|
||
|
if (m2exp < BITS_PER_MP_LIMB)
|
||
|
{
|
||
|
/* Only necessary when M may be smaller than C. */
|
||
|
*rp &= (((mp_limb_t) 1 << m2exp) - 1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* M is not a power of 2. */
|
||
|
abort (); /* FIXME. */
|
||
|
}
|
||
|
|
||
|
/* Save result as next seed. */
|
||
|
*seedp = *rp;
|
||
|
SIZ (rstate->seed) = 1;
|
||
|
return BITS_PER_MP_LIMB;
|
||
|
}
|
||
|
|
||
|
ap = PTR (rstate->algdata.lc->a);
|
||
|
an = SIZ (rstate->algdata.lc->a);
|
||
|
|
||
|
/* Allocate temporary storage. Let there be room for calculation of
|
||
|
(A * seed + C) % M, or M if bigger than that. */
|
||
|
|
||
|
ASSERT_ALWAYS (m2exp != 0); /* FIXME. */
|
||
|
|
||
|
TMP_MARK (mark);
|
||
|
ta = an + seedn + 1;
|
||
|
tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB);
|
||
|
MPN_ZERO (tp, ta);
|
||
|
|
||
|
/* t = a * seed */
|
||
|
if (seedn >= an)
|
||
|
mpn_mul_basecase (tp, seedp, seedn, ap, an);
|
||
|
else
|
||
|
mpn_mul_basecase (tp, ap, an, seedp, seedn);
|
||
|
tn = an + seedn;
|
||
|
|
||
|
/* t = t + c */
|
||
|
mpn_incr_u (tp, c);
|
||
|
|
||
|
/* t = t % m */
|
||
|
if (m2exp != 0)
|
||
|
{
|
||
|
/* M is a power of 2. The mod operation is trivial. */
|
||
|
|
||
|
tp[m2exp / BITS_PER_MP_LIMB] &= ((mp_limb_t) 1 << m2exp % BITS_PER_MP_LIMB) - 1;
|
||
|
tn = (m2exp + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
abort (); /* FIXME. */
|
||
|
}
|
||
|
|
||
|
/* Save result as next seed. */
|
||
|
MPN_COPY (PTR (rstate->seed), tp, tn);
|
||
|
SIZ (rstate->seed) = tn;
|
||
|
|
||
|
if (m2exp != 0)
|
||
|
{
|
||
|
/* Discard the lower half of the result. */
|
||
|
unsigned long int discardb = m2exp / 2;
|
||
|
mp_size_t discardl = discardb / BITS_PER_MP_LIMB;
|
||
|
|
||
|
tn -= discardl;
|
||
|
if (tn > 0)
|
||
|
{
|
||
|
if (discardb % BITS_PER_MP_LIMB != 0)
|
||
|
{
|
||
|
mpn_rshift (tp, tp + discardl, tn, discardb % BITS_PER_MP_LIMB);
|
||
|
MPN_COPY (rp, tp, (discardb + BITS_PER_MP_LIMB -1) / BITS_PER_MP_LIMB);
|
||
|
}
|
||
|
else /* Even limb boundary. */
|
||
|
MPN_COPY_INCR (rp, tp + discardl, tn);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MPN_COPY (rp, tp, tn);
|
||
|
}
|
||
|
|
||
|
TMP_FREE (mark);
|
||
|
|
||
|
/* Return number of valid bits in the result. */
|
||
|
if (m2exp != 0)
|
||
|
retval = (m2exp + 1) / 2;
|
||
|
else
|
||
|
retval = SIZ (rstate->algdata.lc->m) * BITS_PER_MP_LIMB - shiftcount;
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
#ifdef RAWRANDEBUG
|
||
|
/* Set even bits to EVENBITS and odd bits to ! EVENBITS in RP.
|
||
|
Number of bits is m2exp in state. */
|
||
|
/* FIXME: Remove. */
|
||
|
unsigned long int
|
||
|
lc_test (mp_ptr rp, gmp_randstate_t s, const int evenbits)
|
||
|
{
|
||
|
unsigned long int rn, nbits;
|
||
|
int f;
|
||
|
|
||
|
nbits = s->algdata.lc->m2exp / 2;
|
||
|
rn = nbits / BITS_PER_MP_LIMB + (nbits % BITS_PER_MP_LIMB != 0);
|
||
|
MPN_ZERO (rp, rn);
|
||
|
|
||
|
for (f = 0; f < nbits; f++)
|
||
|
{
|
||
|
mpn_lshift (rp, rp, rn, 1);
|
||
|
if (f % 2 == ! evenbits)
|
||
|
rp[0] += 1;
|
||
|
}
|
||
|
|
||
|
return nbits;
|
||
|
}
|
||
|
#endif /* RAWRANDEBUG */
|
||
|
|
||
|
void
|
||
|
#if __STDC__
|
||
|
_gmp_rand (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits)
|
||
|
#else
|
||
|
_gmp_rand (rp, rstate, nbits)
|
||
|
mp_ptr rp;
|
||
|
gmp_randstate_t rstate;
|
||
|
unsigned long int nbits;
|
||
|
#endif
|
||
|
{
|
||
|
mp_size_t rn; /* Size of R. */
|
||
|
|
||
|
rn = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
|
||
|
|
||
|
switch (rstate->alg)
|
||
|
{
|
||
|
case GMP_RAND_ALG_LC:
|
||
|
{
|
||
|
unsigned long int rbitpos;
|
||
|
int chunk_nbits;
|
||
|
mp_ptr tp;
|
||
|
mp_size_t tn;
|
||
|
TMP_DECL (lcmark);
|
||
|
|
||
|
TMP_MARK (lcmark);
|
||
|
|
||
|
chunk_nbits = rstate->algdata.lc->m2exp / 2;
|
||
|
tn = (chunk_nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
|
||
|
|
||
|
tp = (mp_ptr) TMP_ALLOC (tn * BYTES_PER_MP_LIMB);
|
||
|
|
||
|
rbitpos = 0;
|
||
|
while (rbitpos + chunk_nbits <= nbits)
|
||
|
{
|
||
|
mp_ptr r2p = rp + rbitpos / BITS_PER_MP_LIMB;
|
||
|
|
||
|
if (rbitpos % BITS_PER_MP_LIMB != 0)
|
||
|
{
|
||
|
mp_limb_t savelimb, rcy;
|
||
|
/* Target of of new chunk is not bit aligned. Use temp space
|
||
|
and align things by shifting it up. */
|
||
|
lc (tp, rstate);
|
||
|
savelimb = r2p[0];
|
||
|
rcy = mpn_lshift (r2p, tp, tn, rbitpos % BITS_PER_MP_LIMB);
|
||
|
r2p[0] |= savelimb;
|
||
|
/* bogus */ if ((chunk_nbits % BITS_PER_MP_LIMB + rbitpos % BITS_PER_MP_LIMB)
|
||
|
> BITS_PER_MP_LIMB)
|
||
|
r2p[tn] = rcy;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Target of of new chunk is bit aligned. Let `lc' put bits
|
||
|
directly into our target variable. */
|
||
|
lc (r2p, rstate);
|
||
|
}
|
||
|
rbitpos += chunk_nbits;
|
||
|
}
|
||
|
|
||
|
/* Handle last [0..chunk_nbits) bits. */
|
||
|
if (rbitpos != nbits)
|
||
|
{
|
||
|
mp_ptr r2p = rp + rbitpos / BITS_PER_MP_LIMB;
|
||
|
int last_nbits = nbits - rbitpos;
|
||
|
tn = (last_nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
|
||
|
lc (tp, rstate);
|
||
|
if (rbitpos % BITS_PER_MP_LIMB != 0)
|
||
|
{
|
||
|
mp_limb_t savelimb, rcy;
|
||
|
/* Target of of new chunk is not bit aligned. Use temp space
|
||
|
and align things by shifting it up. */
|
||
|
savelimb = r2p[0];
|
||
|
rcy = mpn_lshift (r2p, tp, tn, rbitpos % BITS_PER_MP_LIMB);
|
||
|
r2p[0] |= savelimb;
|
||
|
if (rbitpos + tn * BITS_PER_MP_LIMB - rbitpos % BITS_PER_MP_LIMB < nbits)
|
||
|
r2p[tn] = rcy;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MPN_COPY (r2p, tp, tn);
|
||
|
}
|
||
|
/* Mask off top bits if needed. */
|
||
|
if (nbits % BITS_PER_MP_LIMB != 0)
|
||
|
rp[nbits / BITS_PER_MP_LIMB]
|
||
|
&= ~ ((~(mp_limb_t) 0) << nbits % BITS_PER_MP_LIMB);
|
||
|
}
|
||
|
|
||
|
TMP_FREE (lcmark);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
gmp_errno |= GMP_ERROR_UNSUPPORTED_ARGUMENT;
|
||
|
break;
|
||
|
}
|
||
|
}
|