def calculate_stabilities(self, instance, challenge_prng): """ Calculate the stability for random chosen challenges. :param instance: SimulationMajorityLTFArray A simulation of a Majority Vote Arbiter PUF. :param challenge_prng: RandomState Pseudo-random number generator which is used to generate challenges. """ challenges = np.array( list( tools.random_inputs(self.n, self.N, random_instance=challenge_prng))) eval_array = np.zeros(len(challenges)) # Evaluation of the PUF in order to measure the stability for i in range(self.iterations): eval_array = eval_array + instance.eval(challenges) # Calculation of the stability for every challenge stab_array = (np.abs(eval_array) + self.iterations) / (2 * self.iterations) # Number which counts the satisfying challenges num_goal_fulfilled = 0 # Check of the desired_stability for i in range(self.N): if stab_array[i] >= self.desired_stability: num_goal_fulfilled += 1 # Relative frequency self.overall_stab = num_goal_fulfilled / self.N
def test_transformations_combiner(self): """ This test checks all combinations of transformations and combiners for SimulationMajorityLTFArray to run. """ noise_prng = RandomState(seed=0xC0FFEE) weight_prng1 = RandomState(seed=0xBADA55) crp_count = 16 # number of random inputs per test set n = 64 k = 2 mu = 0 sigma = 1 vote_count = 1 weight_array = LTFArray.normal_weights(n, k, mu, sigma, weight_prng1) inputs = tools.random_inputs( n, crp_count, random_instance=RandomState(seed=0xDEADDA7A)) combiners = get_functions_with_prefix('combiner_', SimulationMajorityLTFArray) transformations = get_functions_with_prefix( 'transform_', SimulationMajorityLTFArray) for transformation in transformations: for combiner in combiners: mv_noisy_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=transformation, combiner=combiner, sigma_noise=1, random_instance_noise=noise_prng, vote_count=vote_count, ) mv_noisy_ltf_array.eval(inputs)
def run(self): inputs = random_inputs(self.parameters.n, self.parameters.N, RandomState(self.parameters.seed)) self.responses = self.instance.val(inputs) self.uniqueness = zeros(shape=(self.parameters.k, self.parameters.k)) for (idx1, i1), (idx2, i2) in combinations( enumerate(self.individual_instances), 2): self.uniqueness[idx1, idx2] = average(i1.eval(inputs) * i2.eval(inputs))
def test_majority_voting(self): """This method is used to test if majority vote works. The first test checks for unequal PUF responses with a LTFArray without noise and a SimulationMajorityLTFArray instance with noise. The second test checks if majority voting works and the instance with and without noise generate equal resonses. """ weight_prng1 = RandomState(seed=0xBADA55) noise_prng = RandomState(seed=0xC0FFEE) crp_count = 16 # number of random inputs per test set n = 8 k = 16 mu = 0 sigma = 1 vote_count = 1 weight_array = LTFArray.normal_weights(n, k, mu, sigma, weight_prng1) mv_noisy_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, sigma_noise=1, random_instance_noise=noise_prng, vote_count=vote_count, ) ltf_array = LTFArray(weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor) inputs = tools.random_inputs( n, crp_count, random_instance=RandomState(seed=0xDEADDA7A)) ltf_array_result = ltf_array.eval(inputs) mv_noisy_ltf_array_result = mv_noisy_ltf_array.eval(inputs) # These test checks if the output is different because of noise self.assertFalse( array_equal(ltf_array_result, mv_noisy_ltf_array_result), 'These arrays must be different') # reset pseudo random number generator noise_prng = RandomState(seed=0xC0FFEE) # increase the vote_count in order to get equality vote_count = 2845 mv_noisy_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, sigma_noise=1, random_instance_noise=noise_prng, vote_count=vote_count, ) # This checks if the majority vote works mv_noisy_ltf_array_result = mv_noisy_ltf_array.eval(inputs) assert_array_equal(mv_noisy_ltf_array_result, ltf_array_result)
def test_chi_vectorized(self): """This function checks the return type of this function.""" n = 8 N = 2**int(n / 2) s = random_input(n) inputs = random_inputs(n, N) chi_arr = chi_vectorized(s, inputs) self.assertEqual(len(chi_arr), N, 'The array must contain {0} arrays.'.format(N)) self.assertEqual(chi_arr.dtype, BIT_TYPE, 'The array must be of type {0}'.format(BIT_TYPE))
def test_majority_voting(self): weight_prng1 = RandomState(seed=0xBADA55) noise_prng = RandomState(seed=0xC0FFEE) crp_count = 16 # number of random inputs per test set n = 8 k = 16 mu = 0 sigma = 1 vote_count = 1 weight_array = LTFArray.normal_weights(n, k, mu, sigma, weight_prng1) mv_noisy_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, sigma_noise=1, random_instance_noise=noise_prng, vote_count=vote_count, ) ltf_array = LTFArray(weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor) inputs = array( list( tools.random_inputs( n, crp_count, random_instance=RandomState(seed=0xDEADDA7A)))) ltf_array_result = ltf_array.eval(inputs) mv_noisy_ltf_array_result = mv_noisy_ltf_array.eval(inputs) # These test checks if the output is different because of noise self.assertFalse( array_equal(ltf_array_result, mv_noisy_ltf_array_result), 'These arrays must be different') # reset pseudo random number generator noise_prng = RandomState(seed=0xC0FFEE) # increase the vote_count in order to get equality vote_count = 277 mv_noisy_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, sigma_noise=1, random_instance_noise=noise_prng, vote_count=vote_count, ) # This checks if the majority vote works mv_noisy_ltf_array_result = mv_noisy_ltf_array.eval(inputs) assert_array_equal(mv_noisy_ltf_array_result, ltf_array_result)
def test_poly_mult_div(self): """This method checks the shape and type of two dimensional arrays.""" n = 8 k = 2 N = 2**int(n / 2) challenges_11 = random_inputs(n, N) challenges_01 = array( [transform_challenge_11_to_01(c) for c in challenges_11], dtype=BIT_TYPE) irreducible_polynomial = array([1, 0, 1, 0, 0, 1, 1, 0, 1], dtype=BIT_TYPE) poly_mult_div(challenges_01, irreducible_polynomial, k) self.check_multi_dimensional_array(challenges_01, N, n, BIT_TYPE)
def test_ltf_eval(self): """ Test ltf_eval for correct evaluation of LTFs. """ weight_prng_1 = RandomState(seed=0xBADA55) weight_prng_2 = RandomState(seed=0xBADA55) noise_prng_1 = RandomState(seed=0xC0FFEE) noise_prng_2 = RandomState(seed=0xC0FFEE) N = 100 # number of random inputs per test set for test_parameters in self.test_set: n = test_parameters[0] k = test_parameters[1] mu = test_parameters[2] sigma = test_parameters[3] transformed_inputs = LTFArray.transform_id( tools.random_inputs( n, N, random_instance=RandomState(seed=0xBAADA555)), k) ltf_array = LTFArray( weight_array=LTFArray.normal_weights(n, k, mu, sigma, weight_prng_1), transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, ) noisy_ltf_array = NoisyLTFArray( weight_array=LTFArray.normal_weights(n, k, mu, sigma, weight_prng_2), # weight_prng_2 was seeded identically to weight_prng_1 transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, sigma_noise=1, random_instance=noise_prng_1, ) evaled_ltf_array = ltf_array.ltf_eval(transformed_inputs) assert_array_equal( around(evaled_ltf_array + noise_prng_2.normal( loc=0, scale=1, size=(len(evaled_ltf_array), k)), decimals=10), around(noisy_ltf_array.ltf_eval(transformed_inputs), decimals=10))
def test_ltf_eval(self): """ Test ltf_eval for correct evaluation of LTFs. """ N = 100 # number of random inputs per test set def ltf_eval_slow(challenge, weights): """ evaluate a single challenge with a single ltf specified by weights """ assert len(challenge) == len(weights) - 1 return dot(challenge, weights[:n]) + weights[n] # weights[n] is the bias for test_parameters in self.test_set: n = test_parameters[0] k = test_parameters[1] mu = test_parameters[2] sigma = test_parameters[3] inputs = tools.random_inputs(n, N, random_instance=RandomState(0xA1)) ltf_array = LTFArray( weight_array=LTFArray.normal_weights(n, k, mu, sigma), transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, ) fast_evaluation_result = around(ltf_array.ltf_eval( LTFArray.transform_id(inputs, k)), decimals=8) slow_evaluation_result = [] for challenge in inputs: slow_evaluation_result.append([ ltf_eval_slow(challenge, ltf_array.weight_array[l]) for l in range(k) ]) slow_evaluation_result = around(slow_evaluation_result, decimals=8) self.assertTupleEqual(shape(slow_evaluation_result), (N, k)) self.assertTupleEqual(shape(fast_evaluation_result), (N, k)) assert_array_equal(slow_evaluation_result, fast_evaluation_result)
def test_random_inputs(self): """This checks the shape and type of the returned multidimensional array.""" n = 8 N = 2**(int(n / 2)) rand_arrays = random_inputs(n, N) self.check_multi_dimensional_array(rand_arrays, N, n, BIT_TYPE)
def run(self): self.responses = self.instance.eval( random_inputs(self.parameters.n, self.parameters.N, RandomState(self.parameters.seed)))