// ======================================================================================================== // ======================================================================================================== // **************************************** verifier_regen_funcs.c **************************************** // ======================================================================================================== // ======================================================================================================== #include "common.h" #include "verifier_common.h" #include "verifier_regen_funcs.h" #include // =========================================================================================================== // =========================================================================================================== // Largest integer number NOT greater than argument. So floor(-0.6 + 0.5) = floor(-0.1) = -1.0. So this function // rounds AWAY from 0, which is exactly what we want when arg is negative. float Round(float d) { return (float)floor((double)d + 0.5); } // ======================================================================================================== // ======================================================================================================== // Read in the database of PNs stored during enrollment. This isn't how we will eventually do it, but will // satisfy the prototype requirements for now. int ReadDatabasePNsExact(int str_length, char database_path[str_length], int max_chips, int max_PNs, float **PNR, float **PNF, int database_has_samples, int DEBUG) { int chip_num, rise_fall, PN_num, num_sams, sam_num; float PN_sum, temp_float; char line[str_length]; char *char_ptr; FILE *INFILE; if ( (INFILE = fopen(database_path, "r")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): Could not open PNs database file %s\n", database_path); fflush(stdout); exit(EXIT_FAILURE); } chip_num = 0; rise_fall = 0; PN_num = 0; num_sams = 0; while ( fgets(line, str_length, INFILE) != NULL ) { // There are blank lines between the rise and fall PNs and after each chip. if ( strlen(line) == 0 || strlen(line) == 1 ) { // Sanity check. This should NEVER occur because we don't allow PN_num to get larger than max_PNs below. if ( PN_num > max_PNs ) { printf("ERROR: ReadDatabasePNsExact(): Number of rising and falling PNs must NOT exceed %d\n", max_PNs); fflush(stdout); exit(EXIT_FAILURE); } // Every other blank line, count a new chip. With 1 chip, assume last line in file is blank. if ( rise_fall == 1 ) { // DEBUG //printf("ReadDatabasePNsExact(): DONE reading PN for chip %d\n", chip_num); fflush(stdout); chip_num++; } // DEBUG //printf("ReadDatabasePNsExact(): Chip %d\tFlipping current value of rise_fall flag %d\n", chip_num, rise_fall); fflush(stdout); // Reset PN_num and invert rise_fall flag. Note that we now use separate arrays for the rise and fall PNs. PN_num = 0; rise_fall = !rise_fall; continue; } // Header information is ignored (for now) if ((char_ptr = strtok(line, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for 'V:'!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "V:") != 0 ) { printf("ERROR: ReadDatabasePNsExact(): Expected 'V:' as first token!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for vector number!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for 'O:'!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "O:") != 0 ) { printf("ERROR: ReadDatabasePNsExact(): Expected 'O:' as third token => '%s'!\n", char_ptr); fflush(stdout); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for output number!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for 'C:'!\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "C:") != 0 ) { printf("ERROR: ReadDatabasePNsExact(): Expected 'C:' as fifth token => '%s'!\n", char_ptr); fflush(stdout); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsExact(): No ' ' found in data line for PN cnter!\n"); fflush(stdout); exit(EXIT_FAILURE); } // If 'database_has_samples' is 1, then assume each line in format // 'V: 11 O: 0 C: 2705 319 320 320 320 320 320 320 320 320 320 323 320 320 320 320 320' if ( database_has_samples == 1 ) { // Retrieve the samples, one at a time, to compute the average. sam_num = 0; PN_sum = 0.0; while ( (char_ptr = strtok(NULL, " \t")) != NULL ) { sscanf(char_ptr, "%f", &temp_float); PN_sum += temp_float; sam_num++; } // Sanity check. Number of samples MUST be consistent across all chips and PN lines if ( num_sams == 0 ) num_sams = sam_num; else if ( num_sams != sam_num ) { printf("ERROR: ReadDatabasePNsExact(): Sample number mismatch across PN lines!\n"); fflush(stdout); exit(EXIT_FAILURE); } // Compute the average value. if ( num_sams != 0 ) { // Don't store anything if we've reached the max number of PNs. if ( PN_num < max_PNs ) { if ( rise_fall == 0 ) PNR[chip_num][PN_num] = PN_sum/num_sams; else PNF[chip_num][PN_num] = PN_sum/num_sams; } } else { printf("ERROR: ReadDatabasePNsExact(): Number of sample is 0!\n"); fflush(stdout); exit(EXIT_FAILURE); } } // Else assume only 1 value per line exists -- the average value as a floating point number. else { // Don't store anything if we've reached the max number of PNs. if ( PN_num < max_PNs ) { if ( rise_fall == 0 ) sscanf(line, "%f", &PNR[chip_num][PN_num]); else sscanf(line, "%f", &PNF[chip_num][PN_num]); } } // Increment PN_num unless we have reached maximum value. Files can have more PNs that we use here. if ( PN_num < max_PNs ) PN_num++; else { printf("WARNING: Number of PNs LARGER than %d -- SKIPPING VALUES!\n", max_PNs); fflush(stdout); } } fclose(INFILE); if ( DEBUG == 1 ) printf("ReadDatabasePNsExact(): Number of chips %d\tNumber of samples read from data file %d\n", chip_num, num_sams); fflush(stdout); return chip_num; } // =========================================================================================================== // =========================================================================================================== // Compute the Median values of each of the averaged PNs. This would be done by the server in advance of any // authentication/encryption operations. void ComputeEnrollmentMedianPUFNums(int max_chips, int max_PNs, int num_chips, float **PNR, float **PNF, float *MedianPNR, float *MedianPNF) { float chip_PNs[max_chips]; int chip_num, PN_num; for ( PN_num = 0; PN_num < max_PNs; PN_num++ ) { // Rising PNs for ( chip_num = 0; chip_num < num_chips; chip_num++ ) chip_PNs[chip_num] = PNR[chip_num][PN_num]; MedianPNR[PN_num] = ComputeMedian(max_chips, num_chips, chip_PNs); // Falling PNs for ( chip_num = 0; chip_num < num_chips; chip_num++ ) chip_PNs[chip_num] = PNF[chip_num][PN_num]; MedianPNF[PN_num] = ComputeMedian(max_chips, num_chips, chip_PNs); } return; } // ======================================================================================================== // ======================================================================================================== // Receive 'GO' and send vectors and masks void GoSendVectors(int max_string_len, int max_vecs, int max_outputs, int vec_len_bits, int token_socket_desc, int num_vecs, int num_rise_vecs, int has_masks, unsigned char *first_vecs_b[max_vecs], unsigned char *second_vecs_b[max_vecs], unsigned char *masks[max_vecs], int DEBUG) { char request_str[max_string_len]; struct timeval t0, t1; long elapsed; // **************************************** // ***** Receive "GO signal from token" if ( DEBUG == 1 ) { printf("GSV.1: Waiting 'GO' from token\n"); gettimeofday(&t0, 0); } if ( SockGetB((unsigned char *)request_str, MAX_STRING_LEN, token_socket_desc) != 2 ) { printf("Receive 'GO' request failed"); fflush(stdout); exit(EXIT_FAILURE); } if ( DEBUG == 1 ) { gettimeofday(&t1, 0); elapsed = (t1.tv_sec-t0.tv_sec)*1000000 + t1.tv_usec-t0.tv_usec; printf("\tElapsed %ld us\n\n", (long)elapsed); } // **************************************** // ***** Send the ID vectors to the token if ( DEBUG == 1 ) { printf("GSV.2: Sending vectors to token\n"); gettimeofday(&t0, 0); } // NOTE: It is the responsibility of the verifier to provide enough rising vectors to supply at least 2048 rising and falling PNs but once the // last rising is applied that gets us over the 2048, NO ADDITIONAL rising VECTORS should be applied and the first falling vector should be next. SendVectorsAndMasks(max_string_len, num_vecs, max_vecs, token_socket_desc, num_rise_vecs, vec_len_bits, first_vecs_b, second_vecs_b, has_masks, max_outputs, masks); if ( DEBUG == 1 ) { gettimeofday(&t1, 0); elapsed = (t1.tv_sec-t0.tv_sec)*1000000 + t1.tv_usec-t0.tv_usec; printf("\tElapsed %ld us\n\n", (long)elapsed); } fflush(stdout); return; }