version 1.1.1.1, 2000/09/09 14:12:16 |
version 1.1.1.2, 2003/08/25 16:06:00 |
|
|
length NBITS in RP. RP must have enough space allocated to hold |
length NBITS in RP. RP must have enough space allocated to hold |
NBITS. |
NBITS. |
|
|
Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
|
|
Since m is prime, the least-significant bits of X are just as random as |
Since m is prime, the least-significant bits of X are just as random as |
the most-significant bits. */ |
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 |
/* 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 |
number of valid bits in the result. NOTE: If 'm' is a power of 2 |
(m2exp != 0), discard the lower half of the result. */ |
(m2exp != 0), discard the lower half of the result. */ |
|
|
static |
static |
unsigned long int |
unsigned long int |
#if __STDC__ |
|
lc (mp_ptr rp, gmp_randstate_t rstate) |
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_ptr tp, seedp, ap; |
mp_size_t ta; |
mp_size_t ta; |
mp_size_t tn, seedn, an; |
mp_size_t tn, seedn, an; |
mp_size_t retval; |
|
int shiftcount = 0; |
|
unsigned long int m2exp; |
unsigned long int m2exp; |
mp_limb_t c; |
mp_limb_t c; |
TMP_DECL (mark); |
TMP_DECL (mark); |
|
|
m2exp = rstate->algdata.lc->m2exp; |
m2exp = rstate->_mp_algdata._mp_lc->_mp_m2exp; |
c = (mp_limb_t) rstate->algdata.lc->c; |
|
|
|
seedp = PTR (rstate->seed); |
/* The code below assumes the mod part is a power of two. Make sure |
seedn = SIZ (rstate->seed); |
that is the case. */ |
|
ASSERT_ALWAYS (m2exp != 0); |
|
|
|
c = (mp_limb_t) rstate->_mp_algdata._mp_lc->_mp_c; |
|
|
|
seedp = PTR (rstate->_mp_seed); |
|
seedn = SIZ (rstate->_mp_seed); |
|
|
if (seedn == 0) |
if (seedn == 0) |
{ |
{ |
/* Seed is 0. Result is C % M. */ |
/* Seed is 0. Result is C % M. Assume table is sensibly stored, |
|
with C smaller than M*/ |
*rp = c; |
*rp = c; |
|
|
if (m2exp != 0) |
*seedp = c; |
{ |
SIZ (rstate->_mp_seed) = 1; |
/* M is a power of 2. */ |
return m2exp; |
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); |
ap = PTR (rstate->_mp_algdata._mp_lc->_mp_a); |
an = SIZ (rstate->algdata.lc->a); |
an = SIZ (rstate->_mp_algdata._mp_lc->_mp_a); |
|
|
/* Allocate temporary storage. Let there be room for calculation of |
/* Allocate temporary storage. Let there be room for calculation of |
(A * seed + C) % M, or M if bigger than that. */ |
(A * seed + C) % M, or M if bigger than that. */ |
|
|
ASSERT_ALWAYS (m2exp != 0); /* FIXME. */ |
|
|
|
TMP_MARK (mark); |
TMP_MARK (mark); |
ta = an + seedn + 1; |
ta = an + seedn + 1; |
tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); |
tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); |
MPN_ZERO (tp, ta); |
|
|
|
/* t = a * seed */ |
/* t = a * seed */ |
if (seedn >= an) |
if (seedn >= an) |
mpn_mul_basecase (tp, seedp, seedn, ap, an); |
mpn_mul (tp, seedp, seedn, ap, an); |
else |
else |
mpn_mul_basecase (tp, ap, an, seedp, seedn); |
mpn_mul (tp, ap, an, seedp, seedn); |
tn = an + seedn; |
tn = an + seedn; |
|
|
/* t = t + c */ |
/* t = t + c */ |
mpn_incr_u (tp, c); |
tp[tn] = 0; /* sentinel, stops MPN_INCR_U */ |
|
MPN_INCR_U (tp, tn, c); |
|
|
|
ASSERT_ALWAYS (m2exp / GMP_NUMB_BITS < ta); |
|
|
/* t = t % m */ |
/* t = t % m */ |
if (m2exp != 0) |
tp[m2exp / GMP_NUMB_BITS] &= ((mp_limb_t) 1 << m2exp % GMP_NUMB_BITS) - 1; |
{ |
tn = (m2exp + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; |
/* 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. */ |
/* Save result as next seed. */ |
MPN_COPY (PTR (rstate->seed), tp, tn); |
MPN_COPY (PTR (rstate->_mp_seed), tp, tn); |
SIZ (rstate->seed) = tn; |
SIZ (rstate->_mp_seed) = tn; |
|
|
if (m2exp != 0) |
{ |
{ |
/* Discard the lower m2exp/2 bits of result. */ |
/* Discard the lower half of the result. */ |
unsigned long int bits = m2exp / 2; |
unsigned long int discardb = m2exp / 2; |
mp_size_t xn = bits / GMP_NUMB_BITS; |
mp_size_t discardl = discardb / BITS_PER_MP_LIMB; |
|
|
|
tn -= discardl; |
tn -= xn; |
if (tn > 0) |
if (tn > 0) |
{ |
{ |
if (discardb % BITS_PER_MP_LIMB != 0) |
unsigned int cnt = bits % GMP_NUMB_BITS; |
{ |
if (cnt != 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); |
mpn_rshift (tp, tp + xn, tn, cnt); |
} |
MPN_COPY_INCR (rp, tp, xn + 1); |
else /* Even limb boundary. */ |
} |
MPN_COPY_INCR (rp, tp + discardl, tn); |
else /* Even limb boundary. */ |
} |
MPN_COPY_INCR (rp, tp + xn, tn); |
} |
} |
else |
} |
{ |
|
MPN_COPY (rp, tp, tn); |
|
} |
|
|
|
TMP_FREE (mark); |
TMP_FREE (mark); |
|
|
/* Return number of valid bits in the result. */ |
/* Return number of valid bits in the result. */ |
if (m2exp != 0) |
return (m2exp + 1) / 2; |
retval = (m2exp + 1) / 2; |
|
else |
|
retval = SIZ (rstate->algdata.lc->m) * BITS_PER_MP_LIMB - shiftcount; |
|
return retval; |
|
} |
} |
|
|
#ifdef RAWRANDEBUG |
#ifdef RAWRANDEBUG |
Line 248 lc_test (mp_ptr rp, gmp_randstate_t s, const int evenb |
|
Line 186 lc_test (mp_ptr rp, gmp_randstate_t s, const int evenb |
|
unsigned long int rn, nbits; |
unsigned long int rn, nbits; |
int f; |
int f; |
|
|
nbits = s->algdata.lc->m2exp / 2; |
nbits = s->_mp_algdata._mp_lc->_mp_m2exp / 2; |
rn = nbits / BITS_PER_MP_LIMB + (nbits % BITS_PER_MP_LIMB != 0); |
rn = nbits / GMP_NUMB_BITS + (nbits % GMP_NUMB_BITS != 0); |
MPN_ZERO (rp, rn); |
MPN_ZERO (rp, rn); |
|
|
for (f = 0; f < nbits; f++) |
for (f = 0; f < nbits; f++) |
Line 264 lc_test (mp_ptr rp, gmp_randstate_t s, const int evenb |
|
Line 202 lc_test (mp_ptr rp, gmp_randstate_t s, const int evenb |
|
#endif /* RAWRANDEBUG */ |
#endif /* RAWRANDEBUG */ |
|
|
void |
void |
#if __STDC__ |
|
_gmp_rand (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits) |
_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. */ |
mp_size_t rn; /* Size of R. */ |
|
|
rn = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; |
rn = (nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; |
|
|
switch (rstate->alg) |
switch (rstate->_mp_alg) |
{ |
{ |
case GMP_RAND_ALG_LC: |
case GMP_RAND_ALG_LC: |
{ |
{ |
Line 289 _gmp_rand (rp, rstate, nbits) |
|
Line 220 _gmp_rand (rp, rstate, nbits) |
|
|
|
TMP_MARK (lcmark); |
TMP_MARK (lcmark); |
|
|
chunk_nbits = rstate->algdata.lc->m2exp / 2; |
chunk_nbits = rstate->_mp_algdata._mp_lc->_mp_m2exp / 2; |
tn = (chunk_nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; |
tn = (chunk_nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; |
|
|
tp = (mp_ptr) TMP_ALLOC (tn * BYTES_PER_MP_LIMB); |
tp = (mp_ptr) TMP_ALLOC (tn * BYTES_PER_MP_LIMB); |
|
|
rbitpos = 0; |
rbitpos = 0; |
while (rbitpos + chunk_nbits <= nbits) |
while (rbitpos + chunk_nbits <= nbits) |
{ |
{ |
mp_ptr r2p = rp + rbitpos / BITS_PER_MP_LIMB; |
mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS; |
|
|
if (rbitpos % BITS_PER_MP_LIMB != 0) |
if (rbitpos % GMP_NUMB_BITS != 0) |
{ |
{ |
mp_limb_t savelimb, rcy; |
mp_limb_t savelimb, rcy; |
/* Target of of new chunk is not bit aligned. Use temp space |
/* Target of of new chunk is not bit aligned. Use temp space |
and align things by shifting it up. */ |
and align things by shifting it up. */ |
lc (tp, rstate); |
lc (tp, rstate); |
savelimb = r2p[0]; |
savelimb = r2p[0]; |
rcy = mpn_lshift (r2p, tp, tn, rbitpos % BITS_PER_MP_LIMB); |
rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS); |
r2p[0] |= savelimb; |
r2p[0] |= savelimb; |
/* bogus */ if ((chunk_nbits % BITS_PER_MP_LIMB + rbitpos % BITS_PER_MP_LIMB) |
/* bogus */ if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS) |
> BITS_PER_MP_LIMB) |
> GMP_NUMB_BITS) |
r2p[tn] = rcy; |
r2p[tn] = rcy; |
} |
} |
else |
else |
Line 324 _gmp_rand (rp, rstate, nbits) |
|
Line 255 _gmp_rand (rp, rstate, nbits) |
|
/* Handle last [0..chunk_nbits) bits. */ |
/* Handle last [0..chunk_nbits) bits. */ |
if (rbitpos != nbits) |
if (rbitpos != nbits) |
{ |
{ |
mp_ptr r2p = rp + rbitpos / BITS_PER_MP_LIMB; |
mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS; |
int last_nbits = nbits - rbitpos; |
int last_nbits = nbits - rbitpos; |
tn = (last_nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; |
tn = (last_nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; |
lc (tp, rstate); |
lc (tp, rstate); |
if (rbitpos % BITS_PER_MP_LIMB != 0) |
if (rbitpos % GMP_NUMB_BITS != 0) |
{ |
{ |
mp_limb_t savelimb, rcy; |
mp_limb_t savelimb, rcy; |
/* Target of of new chunk is not bit aligned. Use temp space |
/* Target of of new chunk is not bit aligned. Use temp space |
and align things by shifting it up. */ |
and align things by shifting it up. */ |
savelimb = r2p[0]; |
savelimb = r2p[0]; |
rcy = mpn_lshift (r2p, tp, tn, rbitpos % BITS_PER_MP_LIMB); |
rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS); |
r2p[0] |= savelimb; |
r2p[0] |= savelimb; |
if (rbitpos + tn * BITS_PER_MP_LIMB - rbitpos % BITS_PER_MP_LIMB < nbits) |
if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits) |
r2p[tn] = rcy; |
r2p[tn] = rcy; |
} |
} |
else |
else |
Line 344 _gmp_rand (rp, rstate, nbits) |
|
Line 275 _gmp_rand (rp, rstate, nbits) |
|
MPN_COPY (r2p, tp, tn); |
MPN_COPY (r2p, tp, tn); |
} |
} |
/* Mask off top bits if needed. */ |
/* Mask off top bits if needed. */ |
if (nbits % BITS_PER_MP_LIMB != 0) |
if (nbits % GMP_NUMB_BITS != 0) |
rp[nbits / BITS_PER_MP_LIMB] |
rp[nbits / GMP_NUMB_BITS] |
&= ~ ((~(mp_limb_t) 0) << nbits % BITS_PER_MP_LIMB); |
&= ~ ((~(mp_limb_t) 0) << nbits % GMP_NUMB_BITS); |
} |
} |
|
|
TMP_FREE (lcmark); |
TMP_FREE (lcmark); |
Line 354 _gmp_rand (rp, rstate, nbits) |
|
Line 285 _gmp_rand (rp, rstate, nbits) |
|
} |
} |
|
|
default: |
default: |
gmp_errno |= GMP_ERROR_UNSUPPORTED_ARGUMENT; |
ASSERT (0); |
break; |
break; |
} |
} |
} |
} |