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 test_bias_influence(self): """ This method tests the influence of the bias array. The results should be different. """ n = 8 k = 4 mu = 1 sigma = 0.5 challenges = tools.all_inputs(n) weight_array = SimulationMajorityLTFArray.normal_weights( n, k, mu=mu, sigma=sigma, random_instance=RandomState(0xBADA556)) bias_array = SimulationMajorityLTFArray.normal_weights( 1, k, mu=mu, sigma=sigma * 2, random_instance=RandomState(0xBADAFF1)) biased_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=SimulationMajorityLTFArray.transform_id, combiner=SimulationMajorityLTFArray.combiner_xor, sigma_noise=sigma, random_instance_noise=RandomState(0xCCABAD), bias=bias_array, ) ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=SimulationMajorityLTFArray.transform_id, combiner=SimulationMajorityLTFArray.combiner_xor, sigma_noise=sigma, random_instance_noise=RandomState(0xCCABAD), bias=None, ) self.assertEqual(ltf_array.weight_array.shape, biased_ltf_array.weight_array.shape) bias_array = biased_ltf_array.weight_array[:, -1] bias_array_compared = [ bias == bias_array[0] for bias in bias_array[1:] ] # the bias values should be different for this test. It is possible that they are all equal but this chance is # low. self.assertFalse(array(bias_array_compared).all()) biased_responses = biased_ltf_array.eval(challenges) responses = ltf_array.eval(challenges) # The arithmetic mean of the res self.assertFalse(array_equal(biased_responses, responses))
def create_mv_ltf_arrays(cls, n=8, k=1, instance_count=10, transformation=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=None, mu=0, sigma=1, weight_random_seed=0x123, sigma_noise=0.5, noise_random_seed=0x321, vote_count=3): """ This function can be used to create a list of SimulationMajorityLTFArray. :param n: int Number of stages of the PUF :param k: int Number different LTFArrays :param instance_count: int Number of simulations to be instantiated. :param transformation: A function: array of int with shape(N,k,n), int number of PUFs k -> shape(N,k,n) The function transforms input challenges in order to increase resistance against attacks. :param combiner: A function: array of int with shape(N,k,n) -> array of in with shape(N) The functions combines the outputs of k PUFs to one bit results, in oder to increase resistance against attacks. :param bias: None, float or a two dimensional array of float with shape (k, 1) This bias value or array of bias values will be appended to the weight_array. Use a single value if you want the same bias for all weight_vectors. :param mu: float Mean (“centre”) of the stage weight distribution of the PUF instance simulation. :param sigma: float Standard deviation of the stage weight distribution of the PUF instance simulation. :param weight_random_seed: int The seed which is used to initialize the pseudo-random number generator which is used to generate the stage weights for the arbiter PUF simulation. :param sigma_noise: float Standard deviation of the noise distribution. :param noise_random_seed: int The seed which is used to initialize the pseudo-random number generator which is used to generate the noise for the arbiter PUF simulation. :param vote_count: int Number of evaluations which are used to choose a response with majority vote. :return: list of pypuf.simulation.arbiter_based.ltfarray.SimulationMajorityLTFArray """ instances = [] for seed_offset in range(instance_count): weight_array = LTFArray.normal_weights(n, k, mu, sigma, random_instance=RandomState(weight_random_seed + seed_offset)) instances.append( SimulationMajorityLTFArray( weight_array=weight_array, transform=transformation, combiner=combiner, sigma_noise=sigma_noise, random_instance_noise=RandomState(noise_random_seed + seed_offset), bias=bias, vote_count=vote_count, ) ) return instances
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 run(self): random = RandomState(seed=self.parameters.seed) sigma_noise = NoisyLTFArray.sigma_noise_from_random_weights( self.parameters.n, 1, self.parameters.sigma_noise_ratio) weights = LTFArray.normal_weights(self.parameters.n, self.parameters.k, random_instance=random) instance_mv = SimulationMajorityLTFArray( weights, LTFArray.transform_atf, LTFArray.combiner_xor, sigma_noise, random_instance_noise=random, vote_count=self.parameters.vote_count) self.stability = approx_stabilities(instance_mv, self.parameters.N, self.parameters.samples, random)
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_bias_influence_value(self): """ This method tests the influence of the bias value. The results should be different. """ n = 8 k = 4 mu = 1 sigma = 0.5 challenges = array(list(tools.all_inputs(n))) weight_array = SimulationMajorityLTFArray.normal_weights(n, k, mu=mu, sigma=sigma, random_instance=RandomState(0xBADA556)) bias_value = 2.5 biased_ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=SimulationMajorityLTFArray.transform_id, combiner=SimulationMajorityLTFArray.combiner_xor, sigma_noise=sigma, random_instance_noise=RandomState(0xCCABAD), bias=bias_value, ) ltf_array = SimulationMajorityLTFArray( weight_array=weight_array, transform=SimulationMajorityLTFArray.transform_id, combiner=SimulationMajorityLTFArray.combiner_xor, sigma_noise=sigma, random_instance_noise=RandomState(0xCCABAD), bias=None, ) # the second dimension of the weight_array plus one must be the number of elements in biased weight_array self.assertEqual(shape(ltf_array.weight_array)[1] + 1, shape(biased_ltf_array.weight_array)[1]) bias_array = biased_ltf_array.weight_array[:, -1] bias_array_compared = [bias == bias_array[0] for bias in bias_array] # the bias values should be equal for this tests. self.assertTrue(array(bias_array_compared).all()) biased_responses = biased_ltf_array.eval(challenges) responses = ltf_array.eval(challenges) # The arithmetic mean of the res self.assertFalse(array_equal(biased_responses, responses))
def stability_figure_data(n, k, vote_count, sigma_noise_ratio, num, reps, random): """ Returns a list of stabilities for randomly chosen challenges of randomly chosen MV XOR Arbiter PUF. :param n: Length of arbiter chains :param k: Number of arbiter chains :param vote_count: Number of votes for each chain :param sigma_noise_ratio: sigma_noise to sigma_model ratio of the arbiter chains :param num: number of challenges to compute stability for :param reps: number of samples per challenge to base the stability computation on :param random: random seed for all PRNG used here """ sigma_noise = NoisyLTFArray.sigma_noise_from_random_weights(n, 1, sigma_noise_ratio) weights = LTFArray.normal_weights(n, k, random_instance=random) instance_mv = SimulationMajorityLTFArray(weights, LTFArray.transform_atf, LTFArray.combiner_xor, sigma_noise, random_instance_noise=random, vote_count=vote_count) stabilities = tools.approx_stabilities(instance_mv, num, reps, random) print('{' + ','.join(map(str, stabilities)) + '}')
def run(self): """ Searches for the minimal number of votes which satisfy self.desired_stability and self.overall_desired_stability. The number of votes for a try is given by the interval between self.bottom and self.top. """ # Random number generators instance_prng = RandomState(self.seed_instance) noise_prng = RandomState(self.seed_instance_noise) challenge_prng = RandomState(self.seed_challenges) # Weight array for the instance which should be learned weight_array = LTFArray.normal_weights(self.n, self.k, self.mu, self.sigma, random_instance=instance_prng) self.vote_count = 0 # Search upper bound for binary search while self.overall_stab < self.overall_desired_stability: self.vote_count = self.vote_count * 2 + 1 puf_instance = SimulationMajorityLTFArray( weight_array, LTFArray.transform_id, LTFArray.combiner_xor, self.sigma_noise, random_instance_noise=noise_prng, vote_count=self.vote_count) self.calculate_stabilities(puf_instance, challenge_prng) self.maximum_vote_count = self.vote_count # Binary search loop which is used to find the minimum number of votes in oder to satisfy # self.desired_stability and overall_desired_stability while self.minimum_vote_count < self.maximum_vote_count: # Set the number of vote counts self.vote_count = (self.minimum_vote_count + self.maximum_vote_count) // 2 # self.vote_count must be odd if self.vote_count % 2 == 0: self.vote_count = self.vote_count + 1 puf_instance = SimulationMajorityLTFArray( weight_array, LTFArray.transform_id, LTFArray.combiner_xor, self.sigma_noise, random_instance_noise=noise_prng, vote_count=self.vote_count) self.calculate_stabilities(puf_instance, challenge_prng) # overall_stab vote_count msg = '%f\t' '%i\t' % (self.overall_stab, self.vote_count) # Interval adjustment if self.overall_stab >= self.overall_desired_stability: self.maximum_vote_count = self.vote_count - 1 self.result_vote_count = self.vote_count self.result_overall_stab = self.overall_stab else: self.minimum_vote_count = self.vote_count + 1 self.progress_logger.info(msg)