/*************************************************************************************** Release 3.3: 08/27/2014 Version 3.3 Purpose: This routine implements the DFAST2 evaluation algorithm. Release Notes: FSRs: the feedback shift register polynomials used in this program are same as in the DFAST2 evaluation version document. Contact CableLabs to obtain the electronic copy of the production program that contains different polynomials. F Tables: they are same as in the DFAST2 evaluation document. Contact CableLabs to obtain the electronic copy of the production program that contains different F table contents. Release 3.2 Notes: Poly_SelectBit is initialized to 1. Release 3.3 Notes: Minor text cleanup. File Name: DFAST2 eval source v3.3.c **************************************************************************************/ #include "DFAST2 eval gfe_ext v3.2.h" #include "DFAST2 eval header v3.2.h" #include #include #ifndef DEBUG_FLAG #define DEBUG_FLAG 0 //default mode is non-debug mode #endif #define sampleT1 0 #define sampleT2 30 #define sampleT3 70 #define sampleT4 126 #define sampleT5 142 #define sampleT6 580 #define sampleT7 636 static const int r = 8; // there are 8 stages in each FSR structure /** setting the polynomial A eval version structure **/ static GFE coeffA[8] = { {137,74}, {122,229}, {148,38}, {0,0}, {36,47}, {50,194}, {41,147}, {121,212} }; /** setting the polynomial B eval version structures: B1 and B2 **/ static GFE coeffB1[8] = { {227,176}, {100,195}, {0,0}, {107,84}, {226,95}, {32,5}, {122,229}, {91,92} }; static GFE coeffB2[8] = { {165,188}, {24,28}, {112,202}, {113,94}, {244,230}, {0,0}, {35,47}, {234,22} }; /** setting the polynomial C eval version structures: C1 and C2 **/ static GFE coeffC1[8] = { {192,31}, {3,25}, {151,124}, {0,0}, {28,200}, {23,129}, {45,18}, {69,221} }; static GFE coeffC2[8] = { {35,47}, {128,7}, {62,114}, {170,151}, {55,185}, {0,0}, {224,203}, {53,39} }; /* eval version F substitution tables */ static int F1[256] = {0x5C,0x90,0xC2,0x3C,0xB1,0x01,0xAF,0xAD, 0x6C,0xDA,0xCE,0x31,0x52,0x6A,0x68,0xB2, 0xA0,0xE6,0x06,0x43,0x87,0x05,0x83,0xE7, 0x0B,0x4E,0x92,0xD7,0x07,0xF1,0xFD,0xE1, 0xC3,0x98,0xBB,0x59,0xD0,0xAA,0x19,0x21, 0xCB,0x70,0x33,0x87,0xA2,0xB3,0xF6,0x0C, 0x4F,0x3D,0x24,0x73,0xAB,0x1C,0x53,0xD2, 0x35,0x67,0x9E,0xAE,0xB0,0xCF,0x23,0x5B, 0xF2,0x6F,0x34,0xC8,0x7A,0x4C,0x3A,0xD4, 0xA7,0x6D,0xD3,0xA3,0x89,0x4A,0xE8,0x71, 0x0E,0x72,0x93,0x3E,0xF8,0xFA,0x78,0x99, 0x13,0x11,0x39,0x18,0x1F,0xC4,0x91,0x49, 0xEE,0x8E,0x79,0x60,0xEC,0xBF,0x1E,0x22, 0xFE,0xB9,0x4D,0x0F,0x26,0x51,0x54,0x2F, 0x50,0xB5,0x6B,0x7B,0x69,0xB7,0x94,0xD9, 0x9A,0xA4,0x8F,0x9D,0x96,0x00,0x03,0xD6, 0xFB,0xA6,0x57,0x27,0x02,0xF5,0x86,0xFC, 0xE0,0x8B,0xC0,0x8D,0x97,0x80,0x20,0xD1, 0x42,0x84,0xE9,0xD8,0x46,0x7F,0x48,0x63, 0x81,0x2D,0x95,0x82,0x16,0x15,0xEA,0x5D, 0x29,0x41,0x1A,0xE5,0x58,0xC6,0xE4,0x40, 0x09,0x3B,0x0D,0x1D,0xDF,0x36,0xBC,0xF9, 0xED,0x04,0xD5,0x2C,0x8A,0x7D,0xB6,0xF4, 0x85,0xB4,0x38,0x64,0x9F,0xF7,0x14,0x5E, 0x66,0xBD,0xDC,0x55,0xCD,0x0A,0xDB,0xA9, 0xE2,0x32,0x2A,0x35,0xB8,0x45,0xC7,0x9B, 0xC5,0xA8,0x77,0x2B,0x2E,0x28,0xF0,0x5A, 0xA5,0x8C,0x47,0x1B,0x44,0x3F,0xC9,0xA1, 0xC1,0x30,0xCA,0x77,0x4B,0x08,0xDD,0x7E, 0xEB,0xEF,0x56,0x88,0xAC,0x5F,0x74,0x65, 0x17,0x25,0x62,0xCC,0x10,0xDE,0x6E,0x9C, 0x76,0x61,0xF3,0xBA,0xBE,0x12,0xE3,0xFF }; static int F2[256] = {0xEE,0x22,0x54,0xCE,0x43,0x93,0x41,0x3F, 0xFE,0x6C,0x60,0xC3,0xE4,0xFC,0xFA,0x44, 0x32,0x78,0x98,0xD5,0x19,0x97,0x15,0x79, 0x9D,0xE0,0x24,0x69,0x99,0x83,0x8F,0x73, 0x55,0x2A,0x4D,0xEB,0x62,0x3C,0xAB,0xB3, 0x5D,0x02,0xC5,0x19,0x34,0x45,0x88,0x9E, 0xE1,0xCF,0xB6,0x05,0x3D,0xAE,0xE5,0x64, 0xC7,0xF9,0x30,0x40,0x42,0x61,0xB5,0xED, 0x84,0x01,0xC6,0x5A,0x0C,0xDE,0xCC,0x66, 0x39,0xFF,0x65,0x35,0x1B,0xDC,0x7A,0x03, 0xA0,0x04,0x25,0xD0,0x8A,0x8C,0x0A,0x2B, 0xA5,0xA3,0xCB,0xAA,0xB1,0x56,0x23,0xDB, 0x80,0x20,0x0B,0xF2,0x7E,0x51,0xB0,0xB4, 0x90,0x4B,0xDF,0xA1,0xB8,0xE3,0xE6,0xC1, 0xE2,0x47,0xFD,0x0D,0xFB,0x49,0x26,0x6B, 0x2C,0x36,0x21,0x2F,0x28,0x92,0x95,0x68, 0x8D,0x38,0xE9,0xB9,0x94,0x87,0x18,0x8E, 0x72,0x1D,0x52,0x1F,0x29,0x12,0xB2,0x63, 0xD4,0x16,0x7B,0x6A,0xD8,0x11,0xDA,0xF5, 0x13,0xBF,0x27,0x14,0xA8,0xA7,0x7C,0xEF, 0xBB,0xD3,0xAC,0x77,0xEA,0x58,0x76,0xD2, 0x9B,0xCD,0x9F,0xAF,0x71,0xC8,0x4E,0x8B, 0x7F,0x96,0x67,0xBE,0x1C,0x0F,0x48,0x86, 0x17,0x46,0xCA,0xF6,0x31,0x89,0xA6,0xF0, 0xF8,0x4F,0x6E,0xE7,0x5F,0x9C,0x6D,0x3B, 0x74,0xC4,0xBC,0xC7,0x4A,0xD7,0x59,0x2D, 0x57,0x3A,0x09,0xBD,0xC0,0xBA,0x82,0xEC, 0x37,0x1E,0xD9,0xAD,0xD6,0xD1,0x5B,0x33, 0x53,0xC2,0x5C,0x09,0xDD,0x9A,0x6F,0x10, 0x7D,0x81,0xE8,0x1A,0x3E,0xF1,0x06,0xF7, 0xA9,0xB7,0xF4,0x5E,0xA2,0x70,0x00,0x2E, 0x08,0xF3,0x85,0x4C,0x50,0xA4,0x75,0x91 }; unsigned int gf2_m; // Galois Filed parameters: GF(2^8), gf2_m = 2^8 = 256 unsigned int exponent[ARR_LIMIT],binary[ARR_LIMIT]; // look-up table array /* global variable */ char copyright[64] = "(C)1999 Cable Labs. All Rights Reserved."; #if DEBUG_FLAG FILE *debug_out; int m; #endif void dfast2(unsigned int *SeedIn, unsigned int *KeyOut) { int S_Box[256]; // S_Box Array int i,j,k; GFE poly_SelectByte; // variable for Select Chain Buffer input int poly_SelectBit = 1; // variable for the DLU output GFE PREKEYSTREAM, STRMFDBCK; // Prekeystream register & codestream register input GFE PKSP, SFBP; // old values for PREKEYSTREAM & STRMFDBCK GFE KSOUT; // variable for keystream before applying the sampling rate GFE g0, g1, RGB7_0, RGA7_0; // intermedia variables GFE RGA07_f1, RGB16_f1, RGA16_f1, RGB07_f1; // intermediate variables GFE RGA5_f1, RGA3_f1, RGB4_f1, RGB2_f1; // intermediate variables GFE registerA[8], registerB[8], registerC[8]; // register contents #if DEBUG_FLAG //if debug is turned on, all the debug results are written //to a file - "debug.log" debug_out = fopen("debug.log", "wt"); #endif #if DEBUG_FLAG fprintf(debug_out, "Input Seed Data: \n"); fprintf(debug_out, "++++++++++++++++++++++++++++++++++++++++++++++++++\n"); for (i = 0; i < 16; i++) fprintf(debug_out, "0x%02X ", SeedIn[i]); fprintf(debug_out, "\n\n"); #endif /** Initializing the S-Box **/ for (i = 0; i < 256; i++) S_Box[i] = i; /** Initializing Field element look-up table **/ init_field(); /** Using SeedIn data to initialize eval version shift register A, B, C content **/ for (i = 0; i < r; i++) { registerB[i].bin = SeedIn[i]; registerB[i].expo = exponent[registerB[i].bin]; registerC[i].bin = SeedIn[i+8]; registerC[i].expo = exponent[registerC[i].bin]; } for (i = 0; i < r/2; i++) { registerA[i].bin = SeedIn[i]; registerA[i].expo = exponent[registerA[i].bin]; } for (i = r/2; i < r; i++) { registerA[i].bin = SeedIn[i+r/2]; registerA[i].expo = exponent[registerA[i].bin]; } /** Initiation of Intermediate variables **/ KSOUT.bin = PKSP.bin = 0; KSOUT.expo = PKSP.expo = 0; PREKEYSTREAM.bin = STRMFDBCK.bin = 0; PREKEYSTREAM.expo = STRMFDBCK.expo = 0; g0.bin = g1.bin = 0; g0.expo = g1.expo = 0; RGA7_0.bin = RGB7_0.bin = 0; RGA7_0.expo = RGB7_0.expo =0; #if DEBUG_FLAG fprintf(debug_out, "Register A Contents (round 0): \n"); fprintf(debug_out, "=================================\n"); for (i = 0; i < 8; i++) fprintf(debug_out, "(%d,%d) ", registerA[i].bin, registerA[i].expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Register B Contents (round 0): \n"); fprintf(debug_out, "=================================\n"); for (i = 0; i < 8; i++) fprintf(debug_out, "(%d,%d) ", registerB[i].bin, registerB[i].expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Register C Contents (round 0): \n"); fprintf(debug_out, "=================================\n"); for (i = 0; i < 8; i++) fprintf(debug_out, "(%d,%d) ", registerC[i].bin, registerC[i].expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Initial Values of Non-linear Mix Functions (round 0): \n"); fprintf(debug_out, "-----------------------------------------------------\n"); fprintf(debug_out, "g0(%d,%d), g1(%d,%d)", g0.bin, g0.expo, g1.bin, g1.expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Initial PREKEYSTREAM (Y0) & STRMFDBCK (Y1) (round 0): \n"); fprintf(debug_out, "******************************************************\n"); fprintf(debug_out, "Y0(%d,%d), Y1(%d,%d)", PREKEYSTREAM.bin, PREKEYSTREAM.expo, STRMFDBCK.bin, STRMFDBCK.expo); fprintf(debug_out, "\n\n"); #endif /** Start the Process ... (assume 7 bytes output is required) **/ j = 0; for (i = 1; i <= (sampleT7+clk_Cycles); i++) { /* KeyOut and poly_SelectByte are 2 clocks ahead of PREKEYSTREAM, and they are computed first before PREKEYSTREAM is updated. */ k = i % 2; if (k==1) { // i = odd, store KeyOut KSOUT = PKSP; // discard output if((i==clk_Cycles+sampleT1)||(i==clk_Cycles+sampleT2) ||(i==clk_Cycles+sampleT3)||(i==clk_Cycles+sampleT4) ||(i==clk_Cycles+sampleT5)||(i==clk_Cycles+sampleT6) ||(i==clk_Cycles+sampleT7)) { KeyOut[j] = (unsigned long) KSOUT.bin; j++; } } /* if (k==1) */ else { // i = even, store poly_SelectByte, and compute poly_SelectBit poly_SelectByte = PKSP; poly_SelectBit = F2[poly_SelectByte.bin] & 0x01; } PKSP = PREKEYSTREAM; SFBP = STRMFDBCK; #if DEBUG_FLAG if((i<10)||(i%256==0)) { fprintf(debug_out, "\n\nPrevious PREKEYSTREAM (PKSP) & STRMFDBCK (SFBP) (round %d): \n",(i-1)); fprintf(debug_out, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); fprintf(debug_out, "PKSP(%d,%d), SFBP(%d,%d)", PKSP.bin, PKSP.expo, SFBP.bin, SFBP.expo); fprintf(debug_out, "\n\n"); } #endif RGA07_f1.bin = F1[mux(registerC[6].bin, registerA[0].bin, registerA[7].bin)]; RGA07_f1.expo = exponent[RGA07_f1.bin]; RGB16_f1.bin = F1[mux(registerC[0].bin, registerB[1].bin, registerB[6].bin)]; RGB16_f1.expo = exponent[RGB16_f1.bin]; RGA16_f1.bin = F1[mux(registerC[6].bin, registerA[1].bin, registerA[6].bin)]; RGA16_f1.expo = exponent[RGA16_f1.bin]; RGB07_f1.bin = F1[mux(registerC[0].bin, registerB[0].bin, registerB[7].bin)]; RGB07_f1.expo = exponent[RGB07_f1.bin]; RGA5_f1.bin = F1[registerA[5].bin]; RGA5_f1.expo = F1[RGA5_f1.bin]; RGB4_f1.bin = F1[registerB[4].bin]; RGB4_f1.expo = exponent[RGB4_f1.bin]; RGA3_f1.bin = F1[registerA[3].bin]; RGA3_f1.expo = F1[RGA3_f1.bin]; RGB2_f1.bin = F1[registerB[2].bin]; RGB2_f1.expo = exponent[RGB2_f1.bin]; // Compute non-linear Mix Function => g0 and g1 g0 = add(mult(RGA07_f1, RGB16_f1), add(mult(registerA[4], RGB2_f1), mult(RGA5_f1, registerB[3]))); g1 = add(mult(RGA16_f1, RGB07_f1), add(mult(registerA[2], RGB4_f1), mult(RGA3_f1, registerB[5]))); // Compute S-Box substitution RGA7_0.bin = mux(registerC[6].bin, registerA[7].bin, registerA[0].bin); RGA7_0.expo = exponent[RGA7_0.bin]; RGB7_0.bin = mux(registerC[0].bin, registerB[7].bin, registerB[0].bin); RGB7_0.expo = exponent[RGB7_0.bin]; S_Substitution(i, g0, g1, RGB7_0, RGA7_0, S_Box, &PREKEYSTREAM, &STRMFDBCK); #if DEBUG_FLAG if((i<10)||(i%256==0)) { fprintf(debug_out, "Output from Non-linear Mix Functions (round %d): \n",i); fprintf(debug_out, "-------------------------------------------------\n"); fprintf(debug_out, "g0(%d,%d), g1(%d,%d)", g0.bin, g0.expo, g1.bin, g1.expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Current PREKEYSTREAM (Y0) & STRMFDBCK (Y1) (round %d): \n",i); fprintf(debug_out, "********************************************************\n"); fprintf(debug_out, "Y0(%d,%d), Y1(%d,%d)", PREKEYSTREAM.bin, PREKEYSTREAM.expo, STRMFDBCK.bin, STRMFDBCK.expo); fprintf(debug_out, "\n\n"); } #endif // Shifting the registers fsra(coeffA, registerA); if(poly_SelectBit) { fsrb(coeffB1, registerB, SFBP); fsrb(coeffC1, registerC, SFBP); } else { fsrb(coeffB2, registerB, SFBP); fsrb(coeffC2, registerC, SFBP); } #if DEBUG_FLAG if((i<10)||(i%256==0)) { fprintf(debug_out, "Register A Contents (round %d): \n", i); fprintf(debug_out, "=================================\n"); for (m = 0; m < 8; m++) fprintf(debug_out, "(%d,%d) ", registerA[m].bin, registerA[m].expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Register B Contents (round %d): \n", i); fprintf(debug_out, "=================================\n"); for (m = 0; m < 8; m++) fprintf(debug_out, "(%d,%d) ", registerB[m].bin, registerB[m].expo); fprintf(debug_out, "\n\n"); fprintf(debug_out, "Register C Contents (round %d): \n", i); fprintf(debug_out, "=================================\n"); for (m = 0; m < 8; m++) fprintf(debug_out, "(%d,%d) ", registerC[m].bin, registerC[m].expo); fprintf(debug_out, "\n\n"); } #endif } /* end for (i = 0; i <= 2*7*s_Rate+clk_Cycles; i++) */ #if DEBUG_FLAG fprintf(debug_out, "Output Key Data: \n"); fprintf(debug_out, "=================================\n"); for (i = 0; i < 7; i++) fprintf(debug_out, "0x%02X ", KeyOut[i]); fprintf(debug_out, "\n\n"); #endif #if DEBUG_FLAG fclose(debug_out); #endif } /* dfast2() */ /************************************************************************ Routine: fsra() for structure A Description: perform feedback shift register operations for structure A (static feedback shift register). Input Parameters: reg: contents of structure A. coeff: polynomial coefficients of structure A. Output: reg: updated (shifted) structure A. *************************************************************************/ void fsra(GFE coeff[], GFE reg[]) { GFE feedback; int stage_cnt; feedback = reg[r-1]; for(stage_cnt=r-1; stage_cnt>0; stage_cnt--) reg[stage_cnt] = add(reg[stage_cnt-1], mult(coeff[stage_cnt],feedback)); reg[0] = mult(coeff[0],feedback); } /******************************************************************* Routine: fsrb() for register structure B and C Description: perform dynamic feedback shift register operations for structure B & C. Input Parameters: coeff: polynomial coefficients of the structure B or C. reg: contents of structure B or C . codestream: codestream content (referred to as Y1 in the block diagram). Output: reg: updated (shifted) register B or C. ********************************************************************/ void fsrb(GFE coeff[], GFE reg[], GFE codestream) { GFE feedback; int stage_cnt; feedback.bin = reg[r-1].bin ^ codestream.bin; feedback.expo = exponent[feedback.bin]; for(stage_cnt=r-1; stage_cnt>0; stage_cnt--) reg[stage_cnt] = add(reg[stage_cnt-1], mult(coeff[stage_cnt],feedback)); reg[0] = mult(coeff[0],feedback); } /**************************************************************************** Routine: S_Substitution() Processing: perform S-Box Substitution function: updating the S-box array and generating output Y0 and Y1. Input Parameters: n: loop counter that is used as the index of S-Box in this routine. It is used to make sure every element in S-Box is changed. g0 & g1: intermediate results (type of GFE) generated from non-linear mix function I. rgA & rgB: output(type of GFE) from pre-determined FSR stages. Y0 & Y1: a pointer to the buffer that holds the outputs generated from S-Box Substitution function. Output: S_Box: updated S-Box array. Y0 & Y1: updated outputs generated from S-Box Substitution function. *****************************************************************************/ void S_Substitution(int n, GFE g0, GFE g1, GFE rgB, GFE rgA, int S_Box[], GFE *Y0, GFE *Y1) { int temp; int y0, y1, t0, t1; n = n % 256; y0 = (g0.bin + S_Box[rgB.bin] + S_Box[n]) % 256; temp = S_Box[y0]; S_Box[y0] = S_Box[n]; S_Box[n] = temp; y1 = (g1.bin + S_Box[rgA.bin] + S_Box[n]) % 256; temp = S_Box[y1]; S_Box[y1] = S_Box[n]; S_Box[n] = temp; t0 = (S_Box[g1.bin] + S_Box[y0]) % 256; t1 = (S_Box[g0.bin] + S_Box[y1]) % 256; Y0->bin = S_Box[t0]; Y1->bin = S_Box[t1]; Y0->expo = exponent[Y0->bin]; Y1->expo = exponent[Y1->bin]; } /************************************************************************ Routine: mux() Purpose: perform 2:1 bitwise multiplexing function. Input Parameters: SEL: 8-bit value that selects inputs from either A or B on a bitwise basis. A: first input - each bit selected if the corresponding bit in SEL is 1. B: second input - each bit selected if the corresponding bit in SEL is 0. Return Value: 8-bit value selected from input A or B on a bitwise basis. ************************************************************************/ int mux (int SEL, int A, int B) { int mux_return; mux_return = (~SEL & B) | (SEL & A); return (mux_return); } /********************************************************************** Routine: init_field() Purpose: initilize the field look-up table ***********************************************************************/ void init_field(void) { unsigned int x=1,xm,tt; unsigned int n; /* FILE *in; in = fopen("GF2_8_435.txt", "w"); */ /* fill field tables for easy multiplication and easy addition */ for(n=0; ngf2_m/2) xm = gf2_m; else xm = 0; binary[n] = (unsigned char)x; tt = ((xm & PrimPoly_gen & gf2_m) ^ ((x<<1)&gf2_m)); x = tt; } for(n=1; n<=gf2_m; n++) exponent[binary[n]] = n-1; /* for(n=0; n<=gf2_m; n++) { fprintf(in, "n %d\tbin %d\t",n,binary[n]); for(nb=gf_m; nb>=0; nb--) fprintf(in, "%1d",(binary[n]>>nb)&0x01); fprintf(in, "\texp %d\n",exponent[binary[n]]); } fclose(in); */ return; } /************************************************************************ Routine: add() Description: perform addition of two nonbinary elements over extended Galois Field GF(2^m) Input Parameters: a & b : nonbinary elements in GF(2^m) Processing: addition over GF(2^m) => bitwise exclusive-OR. Return Values: result of addition operation. *************************************************************************/ GFE add(GFE a, GFE b) { GFE c; c.bin = (a.bin^b.bin) & gf2_m; c.expo = exponent[c.bin]; return c; } /********************************************************************* Routine: mult() Description: perform multiplication of two nonbinary elements over extended Galois Field GF(2^m). Input Parameters: a & b : nonbinary elements in GF(2^m). Processing: multiplication is conducted based on exponential notation. Return Values: result of multiplication operation. **********************************************************************/ GFE mult(GFE a, GFE b) { GFE c; int nz; nz = ((a.bin != 0) & (b.bin !=0)); c.expo = nz*((unsigned char) a.expo + (unsigned char) b.expo)%gf2_m; c.bin = binary[(unsigned char)((c.expo+1)*nz)]; return c; }