// Simulates an n-stage 4 x 4 arbiter PUF with 24-valued inputs and 24-valued outputs. // Each 4 x 4 switch box has 4 inputs and 4 outputs. // The PUF's function is defined by 16n wire delays of switch boxes. // Challenges are genegrated at random. // Prints challenge-response pairs one per line, separated by space. // e.g. if the numebr of stages n = 4 prints // c1 c2 c3 c4 r1 // where r1 is the response to the challenge (c1 c2 c3 c4) #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define SIZE 4 // number of stages n in arbiter PUF #define M 4 #define NUMBER_CHALLENGES 10 #define MEAN 1.0 #define STD_DEV 0.001 typedef struct sbox { float o1; /* 1st output*/ float o2; /* 2nd output */ float o3; /* 3rd output */ float o4; /* 4th output */ float d11; /* delay of wire connecting input 1 and ouptut 1 */ float d12; float d13; float d14; float d21; float d22; float d23; float d24; float d31; float d32; float d33; float d34; float d41; float d42; float d43; float d44; } sbox; static float map(unsigned a, unsigned b); double generateGaussianNoise(double mu, double sigma); static unsigned perm[SIZE][4]; /* challenge bits as a permutation (a,b,c,d) */ static float map(unsigned a, unsigned b); static unsigned ord(float a, float b, float c, float d); /* --------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { unsigned i, j, k, tmp, output, m, p; sbox puf[SIZE+1]; unsigned y[SIZE]; /* 24-valued challenge digits */ unsigned x[SIZE][4][4]; /* one-hot encoded challenge digits y[] */ unsigned counter=0; int seed=(int)time(NULL); srand(seed); /* Assign delays to each sbox */ for(i=0; i < SIZE; i++) { puf[i].d11 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d12 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d13 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d14 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d21 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d22 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d23 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d24 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d31 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d32 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d33 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d34 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d41 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d42 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d43 = generateGaussianNoise(MEAN,STD_DEV); puf[i].d44 = generateGaussianNoise(MEAN,STD_DEV); } //for(i = 0; i < SIZE; i++) { //printf("i = %d:\nd11 = %f, d12 = %f, d13 = %f, d14 = %f\n", i, puf[i].d11, puf[i].d12, puf[i].d13, puf[i].d14); //printf("d21 = %f, d22 = %f, d23 = %f, d24 = %f\n", puf[i].d21, puf[i].d22, puf[i].d23, puf[i].d24); //printf("d31 = %f, d32 = %f, d33 = %f, d34 = %f\n", puf[i].d31, puf[i].d32, puf[i].d33, puf[i].d34); //printf("d41 = %f, d42 = %f, d43 = %f, d44 = %f\n\n", puf[i].d41, puf[i].d42, puf[i].d43, puf[i].d44); //} for(k = 0; k < NUMBER_CHALLENGES; k++) { for(j = 0; j < SIZE; j++) { y[j] = rand()%24; printf("%d ", y[j]); map(y[j],j); for(m = 0; m < 4; m++) { //printf("perm[%d][%d] = %d\n", j, m, perm[j][m]); for(p = 0; p < 4; p++) { if(p == perm[j][m]) { x[j][m][p] = 1; } else { x[j][m][p] = 0; } //printf("%d ", x[j][m][p]); } //printf(")\n"); } } puf[0].o1 = 0; puf[0].o2 = 0; puf[0].o3 = 0; puf[0].o4 = 0; //printf("puf[0].o1 = %f, puf[0].o2 = %f, puf[0].o3 = %f, puf[0].o3 = %f\n", puf[0].o1, puf[0].o2, puf[0].o3, puf[0].o4); for(i = 0; i < SIZE; i++) { puf[i+1].o1 = (puf[i].o1 + puf[i].d11)*x[i][0][0] + (puf[i].o2 + puf[i].d21)*x[i][1][0] + (puf[i].o3 + puf[i].d31)*x[i][2][0] + (puf[i].o4 + puf[i].d41)*x[i][3][0]; puf[i+1].o2 = (puf[i].o1 + puf[i].d12)*x[i][0][1] + (puf[i].o2 + puf[i].d22)*x[i][1][1] + (puf[i].o3 + puf[i].d32)*x[i][2][1] + (puf[i].o4 + puf[i].d42)*x[i][3][1]; puf[i+1].o3 = (puf[i].o1 + puf[i].d13)*x[i][0][2] + (puf[i].o2 + puf[i].d23)*x[i][1][2] + (puf[i].o3 + puf[i].d33)*x[i][2][2] + (puf[i].o4 + puf[i].d43)*x[i][3][2]; puf[i+1].o4 = (puf[i].o1 + puf[i].d14)*x[i][0][3] + (puf[i].o2 + puf[i].d24)*x[i][1][3] + (puf[i].o3 + puf[i].d34)*x[i][2][3] + (puf[i].o4 + puf[i].d44)*x[i][3][3]; //printf("puf[%d].o1 = %f, puf[%d].o2 = %f, puf[%d].o3 = %f, puf[%d].o4 = %f\n", i+1, puf[i+1].o1, i+1, puf[i+1].o2, i+1, puf[i+1].o3, i+1, puf[i+1].o4); } //printf("\n"); output = ord(puf[SIZE].o1, puf[SIZE].o2, puf[SIZE].o3, puf[SIZE].o4); printf("%d\n", output); } return(0); } static float map(unsigned a, unsigned b) { switch(a) { case 0: perm[b][0] = 0; perm[b][1] = 1; perm[b][2] = 2; perm[b][3] = 3; break; case 1: perm[b][0] = 0; perm[b][1] = 1; perm[b][2] = 3; perm[b][3] = 2; break; case 2: perm[b][0] = 0; perm[b][1] = 2; perm[b][2] = 1; perm[b][3] = 3; break; case 3: perm[b][0] = 0; perm[b][1] = 2; perm[b][2] = 3; perm[b][3] = 1; break; case 4: perm[b][0] = 0; perm[b][1] = 3; perm[b][2] = 1; perm[b][3] = 2; break; case 5: perm[b][0] = 0; perm[b][1] = 3; perm[b][2] = 2; perm[b][3] = 1; break; case 6: perm[b][0] = 1; perm[b][1] = 0; perm[b][2] = 2; perm[b][3] = 3; break; case 7: perm[b][0] = 1; perm[b][1] = 0; perm[b][2] = 3; perm[b][3] = 2; break; case 8: perm[b][0] = 1; perm[b][1] = 2; perm[b][2] = 0; perm[b][3] = 3; break; case 9: perm[b][0] = 1; perm[b][1] = 2; perm[b][2] = 3; perm[b][3] = 0; break; case 10: perm[b][0] = 1; perm[b][1] = 3; perm[b][2] = 0; perm[b][3] = 2; break; case 11: perm[b][0] = 1; perm[b][1] = 3; perm[b][2] = 2; perm[b][3] = 0; break; case 12: perm[b][0] = 2; perm[b][1] = 0; perm[b][2] = 1; perm[b][3] = 3; break; case 13: perm[b][0] = 2; perm[b][1] = 0; perm[b][2] = 3; perm[b][3] = 1; break; case 14: perm[b][0] = 2; perm[b][1] = 1; perm[b][2] = 0; perm[b][3] = 3; break; case 15: perm[b][0] = 2; perm[b][1] = 1; perm[b][2] = 3; perm[b][3] = 0; break; case 16: perm[b][0] = 2; perm[b][1] = 3; perm[b][2] = 0; perm[b][3] = 1; break; case 17: perm[b][0] = 2; perm[b][1] = 3; perm[b][2] = 1; perm[b][3] = 0; break; case 18: perm[b][0] = 3; perm[b][1] = 0; perm[b][2] = 1; perm[b][3] = 2; break; case 19: perm[b][0] = 3; perm[b][1] = 0; perm[b][2] = 2; perm[b][3] = 1; break; case 20: perm[b][0] = 3; perm[b][1] = 1; perm[b][2] = 0; perm[b][3] = 2; break; case 21: perm[b][0] = 3; perm[b][1] = 1; perm[b][2] = 2; perm[b][3] = 0; break; case 22: perm[b][0] = 3; perm[b][1] = 2; perm[b][2] = 0; perm[b][3] = 1; break; case 23: perm[b][0] = 3; perm[b][1] = 2; perm[b][2] = 1; perm[b][3] = 0; break; default : printf("Error\n" ); } } static unsigned ord(float a, float b, float c, float d) { if((a < b) && (b < c) && (c < d)) return(0); if((a < b) && (b < d) && (d < c)) return(1); if((a < c) && (c < b) && (b < d)) return(2); if((a < c) && (c < d) && (d < b)) return(3); if((a < d) && (d < b) && (b < c)) return(4); if((a < d) && (d < c) && (c < b)) return(5); if((b < a) && (a < c) && (c < d)) return(6); if((b < a) && (a < d) && (d < c)) return(7); if((b < c) && (c < a) && (a < d)) return(8); if((b < c) && (c < d) && (d < a)) return(9); if((b < d) && (d < a) && (a < c)) return(10); if((b < d) && (d < c) && (c < a)) return(11); if((c < a) && (a < b) && (b < d)) return(12); if((c < a) && (a < d) && (d < b)) return(13); if((c < b) && (b < a) && (a < d)) return(14); if((c < b) && (b < d) && (d < a)) return(15); if((c < d) && (d < a) && (a < b)) return(16); if((c < d) && (d < b) && (b < a)) return(17); if((d < a) && (a < b) && (b < c)) return(18); if((d < a) && (a < c) && (c < b)) return(19); if((d < b) && (b < a) && (a < c)) return(20); if((d < b) && (b < c) && (c < a)) return(21); if((d < c) && (c < a) && (a < b)) return(22); if((d < c) && (c < b) && (b < a)) return(23); return(0); } // code from https://en.wikipedia.org/wiki/Box-Muller_transform double generateGaussianNoise(double mu, double sigma) { static const double epsilon = std::numeric_limits::min(); static const double two_pi = 2.0*3.14159265358979323846; static double z1; static bool generate=false; generate = !generate; if (!generate) return z1 * sigma + mu; double u1, u2; do { u1 = rand() * (1.0 / RAND_MAX); u2 = rand() * (1.0 / RAND_MAX); //cout << "u1:" << u1 << endl; //cout << "u2:" << u2 << endl; } while ( u1 <= epsilon ); double z0; z0 = sqrt(-2.0 * log(u1)) * cos(two_pi * u2); z1 = sqrt(-2.0 * log(u1)) * sin(two_pi * u2); return z0 * sigma + mu; }