package ro.pub.cs.pp.a51hadoop.algorithm.a51; import ro.pub.cs.pp.a51hadoop.algorithm.Hashfn; import ro.pub.cs.pp.a51hadoop.algorithm.a51.A51Bitops; import ro.pub.cs.pp.a51hadoop.algorithm.a51.A51Constants; import ro.pub.cs.pp.a51hadoop.algorithm.a51.A51KeySetup; /* * Apply a hash function on a given string. */ public class A51Hashfn implements Hashfn { /* do we have a majority of set bits in the middle of the * registers? */ public static boolean middle_bit_majority(final int[] R) { int sum = 0; for (int i = 0; i < R.length; i++) sum += A51Bitops.get_ith_bit(R[i], A51Constants.R_middle_pos[i]); return sum >= 2; } /* Clock two or three of R1, R2, R3, with clock control * according to their middle bits. * * Specifically, we clock Ri whenever Ri's middle bit agrees * with the majority value of the three middle bits. */ public static int[] clock(final int[] R) { boolean non_zero_majority = middle_bit_majority(R); int ret[] = new int[3]; for (int i = 0; i < R.length; i++) { int middle_bit = R[i] & (1 << A51Constants.R_middle_pos[i]); boolean middle_bit_non_zero = (middle_bit != 0); boolean middle_bit_is_majoritar = middle_bit_non_zero == non_zero_majority; /* * Only clock Ri when it is the same as the * majority of middle bits */ if (middle_bit_is_majoritar) ret[i] = A51Bitops.clockone(R[i], A51Constants.R_mask[i], A51Constants.R_feedback_taps[i]); else ret[i] = R[i]; } return ret; } /* * Generate an output bit from the current state. * * You grab a bit from each register via the output generation * taps; then you XOR the resulting three bits. */ private static int getbit(final int[] R) { int ret = 0; /* * Original reference implementation XOR-ed * parity(R[i] & (1 << R_out[i])). * * Since R_output_taps[i] only contains single bits, * the argument passed to parity has one or zero bits. * * Moving the given bit with R_output_taps[i] to left * produces the same result. */ for (int i = 0; i < R.length; i++) ret ^= A51Bitops.get_ith_bit(R[i], A51Constants.R_output_taps[i]); return ret; } /* Generate output. * * We generate 228 bits of keystream output. * * The first 114 bits is for the A->B frame; * the next 114 bits is for the B->A frame. * * The buffers are allocate elsewhere each direction, and this * function fills them. */ public static int[] run(int AtoBkeystream[], int BtoAkeystream[], int[] R) { int i; /* Zero out the output buffers. */ for (i = 0; i <= 113/8; i++) AtoBkeystream[i] = BtoAkeystream[i] = 0; /* Generate 114 bits of keystream for the * A->B direction. Store it, MSB first. */ for (i = 0; i < 114; i++) { R = clock(R); AtoBkeystream[i/8] |= getbit(R) << (7 - (i & 7)); } /* Generate 114 bits of keystream for the * B->A direction. Store it, MSB first. */ for (i = 0; i < 114; i++) { R = clock(R); BtoAkeystream[i/8] |= getbit(R) << (7 - (i & 7)); } return R; } private static void printf(String arg) { System.out.print(arg); } public static void test() { int i, failed = 0; int key[] = {0x12, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int frame = 0x134; final int goodAtoB[] = { 0x53, 0x4E, 0xAA, 0x58, 0x2F, 0xE8, 0x15, 0x1A, 0xB6, 0xE1, 0x85, 0x5A, 0x72, 0x8C, 0x00 }; final int goodBtoA[] = { 0x24, 0xFD, 0x35, 0xA3, 0x5D, 0x5F, 0xB6, 0x52, 0x6D, 0x32, 0xF9, 0x06, 0xDF, 0x1A, 0xC0 }; int AtoB[], BtoA[]; AtoB = new int[15]; BtoA = new int[15]; A51KeySetup keysetup = new A51KeySetup(key, frame); int[] R = keysetup.R; int s = R[0] << 23 + 22 | R[1] << 23 | R[2]; R = run(AtoB, BtoA, R); /* Compare against the test vector. */ for (i = 0; i < AtoB.length; i++) if (AtoB[i] != goodAtoB[i]) failed = 1; for (i = 0; i < BtoA.length; i++) if (BtoA[i] != goodBtoA[i]) failed = 1; printf("key: 0x"); for (i=0; i<8; i++) printf(String.format("%02X", key[i])); printf("\n"); printf(String.format("frame number: 0x%06X\n", frame)); printf("known good output:\n"); printf(" A->B: 0x"); for (i=0; i<15; i++) printf(String.format("%02X", goodAtoB[i])); printf(" B->A: 0x"); for (i=0; i<15; i++) printf(String.format("%02X", goodBtoA[i])); printf("\n"); printf("observed output:\n"); printf(" A->B: 0x"); for (i=0; i<15; i++) printf(String.format("%02X", AtoB[i])); printf(" B->A: 0x"); for (i=0; i<15; i++) printf(String.format("%02X", BtoA[i])); printf("\n"); printf("failed=" + failed + "\n"); if (failed == 0) { System.out.println("Self-check succeeded: everything looks ok.\n"); return; } else { // Problems! The test vectors didn't compare System.out.println("\nI don't know why this broke; contact the authors.\n"); } } public String hashfn(String txt) { /* * dummy implementation */ return txt; } public static void main(String[] args) { test(); } }