/*
* `gnu.iou'
* Copyright (C) 2006 John Pritchard.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package gnu.iou;
/**
*
*
* @author John Pritchard
*/
public abstract class prng {
static {
/*
* The DOM uses this class, so it's a good place to initialize
* the filter registry.
*/
gnu.iou.fil.Registry.Defaults();
}
/**
* A scheduler is a minimum priority thread that periodically
* discards a number of random bits from a PRNG, increasing its
* randomness by periodically iterating its deterministic
* sequence.
*
* <p> The scheduler employs a duty cycle upper bound as a number
* of milliseconds between cycles. The actual cycle delay is
* derived from the random value returned by the PRNG.
*
* <p> While the scheduler's "random" cycling is not in itself a
* source of true randomness, its contribution to randomness in
* thread scheduling and randomness in calls to the shared PRNG is
* certainly a component of the total contribution of the
* scheduler to randomness.
*
* <p> A typical PRNG doesn't collect randomness. Any randomness
* in this case is the chance occurance from an external
* perspective.
*
* <p> While this approach contributes only a very weak
* randomness, it can be useful as predicting the resulting PRNG
* output sequence is effectively obviated across shared PRNG
* users: an external user looking at an application's use of a
* shared PRNG will have reduced utility from its local copy of
* the PRNG. This remote PRNG will only be able to predict a
* limited number of bits in the observed PRNG sequence before the
* sequence skips, and the frequency of these skips will be
* tedious to deal with --- at best. It becomes increasingly
* likely, subject to the system's use of the shared PRNG, that a
* remote observer would have better success observing the system
* by other means.
*
* @author John Pritchard
*/
public static class scheduler extends Thread {
private volatile static int tn = 0;
private final java.util.Random prng;
private final long cycle_bound;
private final int bytes_bound;
/**
* @param prng A PRNG to schedule.
*
* @param cycle Upper bound for the delay in milliseconds
* between cycles.
*
* @param bits Upper bound for the number of bits (a multiple
* of eight) to take from the PRNG on each cycle.
*/
public scheduler( java.util.Random prng, long cycle, int bits){
super("gnu.iou.prng$scheduler-"+(tn++));
this.prng = prng;
super.setPriority(MIN_PRIORITY);
super.setDaemon(true);
this.cycle_bound = cycle;
bits/= 8;
if ( 0 == bits)
this.bytes_bound = 1;
else
this.bytes_bound = bits;
}
/**
* A scheduler with a cycle delay of one half second, taking
* eight bits on each cycle.
*
* @param prng A PRNG to schedule.
*/
public scheduler( java.util.Random prng){
this(prng,499,8);
}
public void run(){
try {
/*
* This code is a bit weird.
*
* Both the cycle time and collection bits (bytes
* length) are variables derived from random bits.
*/
long cycle = this.cycle_bound;
int len = this.bytes_bound;
byte[] bits = null;
while(true){
Thread.sleep(cycle);
if ( null == bits || bits.length != len)
bits = new byte[len];
this.prng.nextBytes(bits);
/*
* Next cycle delay.
*/
cycle = (cycle ^ LongXor(bits)) % this.cycle_bound;
if (0 == cycle)
cycle = this.cycle_bound;
/*
* Next number of random bytes.
*/
len = (len ^ IntegerXor(bits)) % this.bytes_bound;
if (0 == len)
len = this.bytes_bound;
continue;
}
}
catch ( InterruptedException intx){
return;
}
}
}
/**
* Scheduler for the Fast PRNG. (The Slow PRNG doesn't have a
* scheduler because a scheduler on the slow PRNG would not be
* practical.)
*/
private static scheduler fastsche = null;
/**
* Shared PRNG initialization monitor.
*/
private final static Object randmon = new Object();
/**
* The fast, shared PRNG for nondeterministic bits is initialized
* on demand.
*/
private volatile static java.util.Random fast = null;
/**
* A shared weak PRNG which is periodically reseeded
*/
public final static java.util.Random Instance(){
synchronized(randmon){
if ( null == fast){
fast = new java.util.Random();
fastsche = new scheduler(fast,500000,64);
fastsche.start();
}
}
return fast;
}
/**
* Eight bytes of random bits
*/
public final static long RandLong(){
return Instance().nextLong();
}
/**
* Eight bytes of random bits
*/
public final static byte[] RandLongBits(){
return Long(Instance().nextLong());
}
/**
* Eight bytes of random bits in a hexidecimal string value.
*/
public final static String RandLongStringHex(){
return chbuf.hex(Long(Instance().nextLong()));
}
/**
* Eight bytes of random bits in a hexidecimal string value.
*/
public final static byte[] RandLongAsciiHex(){
return chbuf.hex_ascii(Long(Instance().nextLong()));
}
/**
* Eight bytes of random bits in a base64 string value.
*/
public final static String RandLongStringB64(){
return new java.lang.String(b64.encode(Long(Instance().nextLong())));
}
/**
* Eight bytes of random bits in a base64 string value.
*/
public final static byte[] RandLongAsciiB64(){
return b64.encode(Long(Instance().nextLong()));
}
/**
* Fast and efficient checksum: XOR- fold input bits into output
* in big- endian order.
*
* <p> Eight bytes representing a big endian long integer will
* produce the value of the integer.
*/
public final static long LongXor ( byte[] b){
if ( null == b) throw new IllegalArgumentException("Null argument for hash function.");
long accum = 0, tmp;
int shift ;
for ( int c = 0, uc = b.length- 1; c < b.length; c++, uc--){
shift = ((uc % 8)<<3);
tmp = (b[c]&0xff);
tmp <<= shift;
accum ^= tmp;
}
return accum;
}
/**
* Fast and efficient checksum: XOR- fold input bits into output
* in big- endian order.
*
* <p> Four bytes representing a big endian integer will produce
* the value of the integer.
*/
public final static int IntegerXor ( byte[] b){
if ( null == b) throw new IllegalArgumentException("Null argument for hash function.");
int accum = 0, tmp;
int shift ;
for ( int c = 0, uc = b.length- 1; c < b.length; c++, uc--){
shift = ((uc % 4)<<2);
tmp = (b[c]&0xff);
tmp <<= shift;
accum ^= tmp;
}
return accum;
}
/**
* Fast and efficient checksum: XOR- fold input bits into output
* in big- endian order.
*
* <p> Two bytes representing a big endian short integer will
* produce the value of the integer.
*/
public final static short ShortXor ( byte[] b){
if ( null == b) throw new IllegalArgumentException("Null argument for hash function.");
short accum = 0, tmp;
int shift ;
for ( int c = 0, uc = b.length- 1; c < b.length; c++, uc--){
shift = ((uc % 2)<<1);
tmp = (short)(b[c]&0xff);
tmp <<= shift;
accum ^= tmp;
}
return accum;
}
/**
* For eight bytes in big- endian order, return their integer
* value.
*/
public final static long Long( byte[] buf, int ofs){
long ret = 0, reg;
int len = buf.length;
if ( 8 < len) len = 8;
for ( int cc = ofs, sh = 56; cc < len; cc++, sh -= 8){
reg = (buf[cc]&0xff);
ret += reg<<sh;
}
return ret;
}
/**
* Eight bytes with the big- endian binary representation of the
* argument value.
*/
public final static byte[] Long( long num){
byte[] ret = new byte[8];
ret[0] = (byte)((num>>>56)&0xff);
ret[1] = (byte)((num>>>48)&0xff);
ret[2] = (byte)((num>>>40)&0xff);
ret[3] = (byte)((num>>>32)&0xff);
ret[4] = (byte)((num>>>24)&0xff);
ret[5] = (byte)((num>>>16)&0xff);
ret[6] = (byte)((num>>>8)&0xff);
ret[7] = (byte)(num&0xff);
return ret;
}
/**
* For eight bytes in big- endian order, return their integer
* value.
*/
public final static int Integer( byte[] buf, int ofs){
int ret = 0, reg;
int len = buf.length;
if ( 4 < len) len = 4;
for ( int cc = ofs, sh = 24; cc < len; cc++, sh -= 4){
reg = (buf[cc]&0xff);
ret += reg<<sh;
}
return ret;
}
/**
* Eight bytes with the big- endian binary representation of the
* argument value.
*/
public final static byte[] Integer( int num){
byte[] ret = new byte[4];
ret[0] = (byte)((num>>>24)&0xff);
ret[1] = (byte)((num>>>16)&0xff);
ret[2] = (byte)((num>>>8)&0xff);
ret[3] = (byte)(num&0xff);
return ret;
}
}