import java.util.zip.*; import java.util.*; public class ChecksumFrier { protected int dataBlockSize; // size of test data in bytes protected int numberOfNoiseBursts; protected int iterations; protected byte[] masterData, testData; // the contenders in the checksumming championship protected CRC32 crc; protected Adler32 adler; protected HomeBrew homeBrew; protected long crcSum, adlerSum, mySum; protected int crcFailures, adlerFailures, myFailures; protected long crcRunTime, adlerRunTime, myRunTime; //------------------------------------------------------------------- // ChecksumFriers Constructor //------------------------------------------------------------------- public ChecksumFrier() { crc = new CRC32(); adler = new Adler32(); homeBrew = new HomeBrew(); // reset failure counters crcFailures = adlerFailures = myFailures = 0; crcRunTime = adlerRunTime = myRunTime = 0; iterations = 0; } //------------------------------------------------------------------- // delegate main to an object of our class. //------------------------------------------------------------------- public static void main (String[] args) { new ChecksumFrier().go(args); } //------------------------------------------------------------------- // go() is the main entry point //------------------------------------------------------------------- protected void go(String[] args) { long timeNow; if ( args.length != 2 ) { System.out.println( "Please specify the size of the data block to checksum and"+ " the number of bits to corrupt per test."); System.exit(10); } dataBlockSize = Integer.parseInt(args[0]); numberOfNoiseBursts = Integer.parseInt(args[1]); System.out.println("Generating test data..."); initializeTest(dataBlockSize); dumpData(masterData); System.out.println(""); System.out.println("Hit CTRL-C to break test..."); System.out.println(""); while (true) { // reset Test Data // use fast native memory blit routine instead of for loop System.arraycopy(masterData , 0, testData , 0, dataBlockSize); // blast a user-definable number of random bits int[] uniqueBits = genNUniqueIntegers(numberOfNoiseBursts, dataBlockSize*8); for (int i=0; i < uniqueBits.length; i++) { flipBit(testData, uniqueBits[i]); // flip a bit } timeNow = System.currentTimeMillis(); if ( ! algorithmDetectsBitChange(crc, crcSum)) { crcFailures++; dumpData(testData); } crcRunTime += System.currentTimeMillis() - timeNow; timeNow = System.currentTimeMillis(); if ( ! algorithmDetectsBitChange(adler, adlerSum)) { adlerFailures++; dumpData(testData); } adlerRunTime += System.currentTimeMillis() - timeNow; timeNow = System.currentTimeMillis(); if ( ! algorithmDetectsBitChange(homeBrew, mySum)) { myFailures++; } myRunTime += System.currentTimeMillis() - timeNow; System.out.print("Test "+ iterations +", fails so far: "); System.out.print(" CRC=" + crcFailures); System.out.print(" (" + (float)crcRunTime/1000 + "s)"); System.out.print(" Adler=" + adlerFailures); System.out.print(" (" + (float)adlerRunTime/1000 + "s)"); System.out.print(" HomeBrew=" + myFailures); System.out.print(" (" + (float)myRunTime/1000 + "s)"); System.out.print("\r"); // not newline, just RETURN System.out.flush(); iterations++; } // endfor } //------------------------------------------------------------------- // Apply one of the Checksum algorithms to the corrupted test data // and see if the algorithm spotted the corruption at all. //------------------------------------------------------------------- protected boolean algorithmDetectsBitChange(Checksum checksum, long masterSum) { checksum.reset(); checksum.update(testData, 0, dataBlockSize); return ! (checksum.getValue() == masterSum); } //------------------------------------------------------------------- // Allocate a master and test array. Fill master array with test data. //------------------------------------------------------------------- protected void initializeTest(int size) { masterData = new byte[size]; testData = new byte[size]; for (int i=0; i < size; i++) { masterData[i] = (byte) (Math.random()*255); } // calculate master checksums crc .update(masterData, 0, dataBlockSize); adler .update(masterData, 0, dataBlockSize); homeBrew.update(masterData, 0, dataBlockSize); crcSum = crc .getValue(); adlerSum = adler .getValue(); mySum = homeBrew.getValue(); } //------------------------------------------------------------------- // Dump data so that we can visually verify any differences //------------------------------------------------------------------- protected void dumpData(byte[] array) { String hex; // dont dump data if dataset to big to fit on a line if ( array.length > 20 ) { return; } System.out.println(""); for (int i=0; i < array.length; i++) { hex = Integer.toHexString(array[i] & 0x00FF); hex = hex.toUpperCase(); System.out.print( hex +" "); } System.out.println(""); } //------------------------------------------------------------------- // Method to generate N unique integers out of 0..range-1 //------------------------------------------------------------------- public static int[] genNUniqueIntegers(int n, int range) { Vector bag = new Vector(); // fill a bag with unique numbers while(bag.size() != n) { int attempt = (int) (Math.random()*range); attempt %= range; Integer val = new Integer(attempt); // if we haven't generated this number before, add it. if ( bag.indexOf(val) == -1) { bag.addElement(val); } } // decant bag to rigid array int[] result = new int[n]; for (int i=0; i < n; i++) { result[i] = ((Integer) (bag.elementAt(i))) .intValue(); } return result; } //------------------------------------------------------------------- // Method to flip bit N in an array of bytes //------------------------------------------------------------------- protected static int[] bitMasks = {1,2,4,8,16,32,64,128}; public static void flipBit(byte[] array, int bit) { int address; byte victim; address = bit/8; // calculate address of byte to corrupt victim = array[address]; // read byte victim ^= bitMasks[bit & 7]; // flip single bit array[address] = victim; // write byte back } } // End of Class ChecksumFrier