def test_ltf_eval(self): """ Test ltf_eval for correct evaluation of LTFs. """ #random.normal(loc=0, scale=self.sigma_noise, size=(1, self.k)) 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( RandomState(seed=0xBAADA555).choice([-1, +1], (N, n)), # bad ass testing 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 prepare(self): """ Initializes the instance, the training set and the learner to then run the logistic regression with the given parameters. """ self.instance = LTFArray( weight_array=LTFArray.normal_weights( self.parameters.n, self.parameters.k, random_instance=RandomState( seed=self.parameters.seed_instance)), transform=self.parameters.transformation, combiner=self.parameters.combiner, ) self.learner = LogisticRegression( tools.TrainingSet(instance=self.instance, N=self.parameters.N, random_instance=RandomState( self.parameters.seed_challenge)), self.parameters.n, self.parameters.k, transformation=self.instance.transform, combiner=self.instance.combiner, weights_prng=RandomState(seed=self.parameters.seed_model), logger=self.progress_logger, minibatch_size=self.parameters.mini_batch_size, convergance_decimals=self.parameters.convergence_decimals or 2, shuffle=self.parameters.shuffle, )
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 pipeline(N): instance = LTFArray( weight_array=LTFArray.normal_weights(n=64, k=2), transform=LTFArray.transform_atf, combiner=LTFArray.combiner_xor ) train_set = tools.TrainingSet(instance=instance, N=N) train_size = int(len(train_set.challenges) * 0.95) val_set = train_set.subset(slice(train_size, None)) train_set = train_set.subset(slice(None, train_size)) lr_learner = LogisticRegression( t_set=train_set, n=64, k=2, transformation=LTFArray.transform_atf, combiner=LTFArray.combiner_xor, ) model = lr_learner.learn() val_set_predicted_responses = model.eval(val_set.challenges) accuracy = accuracy_score(val_set_predicted_responses, val_set.responses) return accuracy
def main(): """ Run an example how to use pypuf. Developers Notice: Changes here need to be mirrored to README! """ # create a simulation with random (Gaussian) weights # for 64-bit 4-XOR instance = LTFArray( weight_array=LTFArray.normal_weights(n=64, k=2), transform=LTFArray.transform_atf, combiner=LTFArray.combiner_xor, ) # create the learner lr_learner = LogisticRegression( t_set=tools.TrainingSet(instance=instance, N=12000), n=64, k=2, transformation=LTFArray.transform_atf, combiner=LTFArray.combiner_xor, ) # learn and test the model model = lr_learner.learn() accuracy = 1 - tools.approx_dist(instance, model, 10000) # output the result print('Learned a 64bit 2-xor XOR Arbiter PUF from 12000 CRPs with accuracy %f' % accuracy)
def run(self): self.instance = LTFArray(weight_array=LTFArray.normal_weights( self.n, self.k, random_instance=self.instance_prng), transform=self.transformation, combiner=self.combiner, bias=0.0) validation_size = int((self.N / 1.1) // 10) self.training_set = TrainingSet(instance=self.instance, N=self.N - validation_size, random_instance=self.challenge_prng) self.validation_set = TrainingSet(instance=self.instance, N=validation_size, random_instance=self.distance_prng) self.learner = CorrelationAttack( n=self.n, k=self.k, training_set=self.training_set, validation_set=self.validation_set, weights_prng=self.model_prng, lr_iteration_limit=self.lr_iteration_limit, mini_batch_size=self.mini_batch_size, convergence_decimals=self.convergence_decimals, shuffle=self.shuffle, logger=self.progress_logger, ) self.model = self.learner.learn()
def test_uniqueness_set(self): """This method tests the uniqueness set generation function.""" n = 8 k = 1 N = 2**n instance_count = 25 measurements = 2 transformation = LTFArray.transform_id combiner = LTFArray.combiner_xor instances = [ LTFArray(weight_array=LTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1 + i)), transform=transformation, combiner=combiner) for i in range(instance_count) ] challenges = sample_inputs(n, N, random_instance=RandomState(0xFAB10)) uniqueness_set = PropertyTest.uniqueness_set(instances, challenges, measurements=measurements) # Check uniqueness_set to have the expected number of elements self.assertEqual(len(uniqueness_set), N * measurements) # For normal distributed weights is the expected uniqueness near 0.5 self.assertEqual(round(mean(uniqueness_set), 1), 0.5)
def test_reliability(self): """This method tests the test_reliability calculation.""" n = 8 k = 8 N = 2**n transformation = LTFArray.transform_id combiner = LTFArray.combiner_xor instance = LTFArray( weight_array=LTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1)), transform=transformation, combiner=combiner, ) challenges = sample_inputs(n, N, random_instance=RandomState(0xFAB1A)) reliabilities = [] for challenge in challenges: reliabilities.append( PropertyTest.reliability(instance, reshape(challenge, (1, n)))) # For noiseless simulations the responses are always the same hence the reliability is 0% assert_array_equal(reliabilities, repeat(0.0, N)) noisy_instance = NoisyLTFArray( weight_array=NoisyLTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1)), transform=transformation, combiner=combiner, sigma_noise=15.0, random_instance=RandomState(0x5015E), ) for challenge in challenges: reliability = PropertyTest.reliability(noisy_instance, reshape(challenge, (1, n))) # For noisy simulations the responses should vary self.assertNotEqual(reliability, 0.0)
def test_learn_ip_mod2(self): """" Stupid test which gains code coverage """ instance_prng = RandomState(seed=TestLogisticRegression.seed_instance) model_prng = RandomState(seed=TestLogisticRegression.seed_model) instance = LTFArray( weight_array=LTFArray.normal_weights( TestLogisticRegression.n, TestLogisticRegression.k, random_instance=instance_prng), transform=LTFArray.transform_id, combiner=LTFArray.combiner_ip_mod2, ) lr_learner = LogisticRegression( TrainingSet(instance=instance, N=TestLogisticRegression.N), TestLogisticRegression.n, TestLogisticRegression.k, transformation=LTFArray.transform_id, combiner=LTFArray.combiner_xor, weights_prng=model_prng, ) lr_learner.learn()
def test_training_set_challenges(self): """The TrainingSet should generate the same challenges for equal seeds.""" n = 8 k = 1 transformation = LTFArray.transform_id combiner = LTFArray.combiner_xor N = 1000 instance_prng = RandomState(0x4EFEA) weight_array = LTFArray.normal_weights(n, k, random_instance=instance_prng) instance = LTFArray( weight_array=weight_array, transform=transformation, combiner=combiner, ) challenge_seed = 0xAB17D training_set_1 = TrainingSet( instance=instance, N=N, random_instance=RandomState(challenge_seed)) training_set_2 = TrainingSet( instance=instance, N=N, random_instance=RandomState(challenge_seed)) self.assertTrue( array_equal(training_set_1.challenges, training_set_2.challenges), 'The challenges are not equal.', )
def test_bias_influence_array(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 = LTFArray.normal_weights( n, k, mu=mu, sigma=sigma, random_instance=RandomState(0xBADA556)) bias_array = LTFArray.normal_weights( 1, k, mu=mu, sigma=sigma * 2, random_instance=RandomState(0xBADAFF1)) biased_ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=bias_array, ) ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=None, ) # the second dimension of the weight_array must be the number of elements in biased weight_array self.assertEqual( shape(ltf_array.weight_array)[1], shape(biased_ltf_array.weight_array)[1]) assert_array_equal(biased_ltf_array.weight_array[:, :n], ltf_array.weight_array[:, :n]) assert_array_equal(biased_ltf_array.weight_array[:, :n], weight_array) assert_array_equal(biased_ltf_array.weight_array[:, n], reshape(bias_array, (k, ))) assert_array_equal(ltf_array.weight_array[:, n], zeros((k, ))) biased_responses = biased_ltf_array.eval(challenges) responses = ltf_array.eval(challenges) self.assertFalse(array_equal(biased_responses, responses))
def test_reliability_statistic(self): """This method tests the reliability statistic of an instance set.""" n = 8 k = 1 N = 2**n instance_count = 2 measurements = 100 transformation = LTFArray.transform_id combiner = LTFArray.combiner_xor instances = [ LTFArray(weight_array=LTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1 + i)), transform=transformation, combiner=combiner) for i in range(instance_count) ] challenges = sample_inputs(n, N, random_instance=RandomState(0xFAB10)) property_test = PropertyTest(instances) reliability_statistic = property_test.reliability_statistic( challenges, measurements=measurements) # For an noiseless set of simulations the reliability must be 0% for key, value in reliability_statistic.items(): if key == 'sv': self.assertEqual(value, 0.0, '{}'.format(key)) elif key == 'samples': self.assertEqual(len(value), instance_count * N, '{}'.format(key)) else: self.assertEqual(value, 0.0, '{}'.format(key)) noisy_instances = [ NoisyLTFArray( weight_array=LTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1 + i)), transform=transformation, combiner=combiner, sigma_noise=0.5, random_instance=RandomState(0xCABE), ) for i in range(instance_count) ] noisy_property_test = PropertyTest(noisy_instances) noisy_reliability_statistic = noisy_property_test.reliability_statistic( challenges, measurements=measurements) self.assertNotEqual(noisy_reliability_statistic['mean'], 0.0)
def test_random_weights(self): for test_parameters in self.test_set: n = test_parameters[0] k = test_parameters[1] mu = test_parameters[2] sigma = test_parameters[3] self.assertTupleEqual( shape(LTFArray.normal_weights(n, k, mu, sigma)), (k, n))
def learn(self): """ Compute a model according to the given LTF Array parameters and training set. Note that this function can take long to return. :return: pypuf.simulation.arbiter_based.LTFArray The computed model. """ # log format def log_state(): """ This method is used to log a snapshot of learning variables while running. """ if self.logger is None: return self.logger.debug( '%i\t%f\t%f\t%s' % (self.iteration_count, distance, norm(updater.step), ','.join( map(str, model.weight_array.flatten())))) # let numpy raise exceptions seterr(all='raise') # we start with a random model model = LTFArray( weight_array=LTFArray.normal_weights(self.n, self.k, self.weights_mu, self.weights_sigma, self.weights_prng), transform=self.transformation, combiner=self.combiner, ) updater = self.RPropModelUpdate(model) converged = False distance = 1 self.iteration_count = 0 log_state() while not converged and self.iteration_count < self.iteration_limit: self.iteration_count += 1 # compute gradient & update model gradient = self.gradient(model) model.weight_array += updater.update(gradient) # check convergence converged = norm(updater.step) < 10**-self.convergence_decimals # log log_state() if not converged: self.converged = False else: self.converged = True return model
def prepare(self): self.set = sample_inputs(self.parameters.n, self.parameters.N, RandomState(seed=self.parameters.seed_input)) self.ltf_array = LTFArray( weight_array=LTFArray.normal_weights(self.parameters.n, self.parameters.k), transform=self.parameters.transform, combiner=self.parameters.combiner, )
def test_random_weights(self): """ This method tests if the shape of the LTFArray generated weights are as expected. """ for test_parameters in self.test_set: n = test_parameters[0] k = test_parameters[1] mu = test_parameters[2] sigma = test_parameters[3] self.assertTupleEqual(shape(LTFArray.normal_weights(n, k, mu, sigma)), (k, n))
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_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_array(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 = array(list(tools.all_inputs(n))) weight_array = LTFArray.normal_weights(n, k, mu=mu, sigma=sigma, random_instance=RandomState(0xBADA556)) bias_array = LTFArray.normal_weights(1, k, mu=mu, sigma=sigma*2, random_instance=RandomState(0xBADAFF1)) biased_ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=bias_array, ) ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, 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[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_parse_file(self): """This method checks reading challenge-response pairs from a file.""" n, k, N = 128, 1, 10 instance = LTFArray(LTFArray.normal_weights(n, k), LTFArray.transform_atf, LTFArray.combiner_xor) original = TrainingSet(instance, N) f = NamedTemporaryFile('w') for vals in column_stack((original.challenges, original.responses)): f.write(' '.join(map(str, vals)) + '\n') f.flush() loaded = parse_file(f.name, n, in_11_notation=True) assert_array_equal(original.challenges, loaded.challenges) assert_array_equal(original.responses, loaded.responses) f.close()
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_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_reliability_set(self): """This method tests the reliability_statistic calculation.""" n = 8 k = 3 N = 2**n measurements = 10 transformation = LTFArray.transform_id combiner = LTFArray.combiner_xor instances = [] instance_count = 3 for i in range(instance_count): instance = LTFArray( weight_array=LTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1 + i)), transform=transformation, combiner=combiner, ) instances.append(instance) challenges = sample_inputs(n, N, random_instance=RandomState(0xFAB0)) reliability_set = PropertyTest.reliability_set( instances, challenges, measurements=measurements) # The result is an array like with N * k entries. self.assertEqual(len(reliability_set), N * instance_count) # For noiseless simulations the all reliabilities must be 0% assert_array_equal(reliability_set, repeat(0.0, N * instance_count)) noisy_instances = [] for i in range(instance_count): noisy_instance = NoisyLTFArray( weight_array=NoisyLTFArray.normal_weights( n=n, k=k, random_instance=RandomState(0xA1A1 + i)), transform=transformation, combiner=combiner, sigma_noise=0.5, random_instance=RandomState(0x5015C + i), ) noisy_instances.append(noisy_instance) noisy_reliability_set = PropertyTest.reliability_set( noisy_instances, challenges, measurements=measurements) # For a noisy simulation the mean reliability must differ from zero self.assertNotEqual(mean(noisy_reliability_set), 0.0)
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(x, w): """ evaluate a single input x with a single ltf specified by weights w """ assert len(x) == len(w) return dot(x, w) for test_parameters in self.test_set: n = test_parameters[0] k = test_parameters[1] mu = test_parameters[2] sigma = test_parameters[3] inputs = RandomState(seed=0xCAFED00D).choice([-1, +1], (N, n)) 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=10) slow_evaluation_result = [] for c in inputs: slow_evaluation_result.append([ ltf_eval_slow(c, ltf_array.weight_array[l]) for l in range(k) ]) slow_evaluation_result = around(slow_evaluation_result, decimals=10) 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_learn_xor(self): """" Stupid test which gains code coverage """ instance_prng = RandomState(seed=TestLowDegree.seed_instance) instance = LTFArray( weight_array=LTFArray.normal_weights( TestLowDegree.n, TestLowDegree.k, random_instance=instance_prng), transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, ) low_degree_learner = LowDegreeAlgorithm(TrainingSet(instance=instance, N=TestLowDegree.N), degree=TestLowDegree.degree) low_degree_learner.learn()
def learn(self): model = LTFArray( weight_array=LTFArray.normal_weights(self.n, self.k, self.weights_mu, self.weights_sigma, self.weights_prng), transform=self.transformation, combiner=self.combiner, ) self.iteration_count = 0 challenges = [] responses = [] challenges.append(ones(self.n)) responses.append( self.__signum(sum(self.orig_LTFArray.weight_array * challenges))) while self.iteration_count < self.iteration_limit: self.__updateModel(model) stderr.write('\riter %5i \n' % (self.iteration_count)) self.iteration_count += 1 [center, radius] = self.__chebyshev_center(challenges, responses) stderr.write("radius ") stderr.write("%f\n" % radius) stderr.write("distance ") model.weight_array = [center] distance = tools.approx_dist(self.orig_LTFArray, model, min(10000, 2**model.n)) self.min_distance = min(distance, self.min_distance) if (distance < 0.01): break minAccuracy = abs(radius * sqrt(model.n)) stderr.write("%f\n" % distance) newC = self.__closest_challenge(center, minAccuracy) challenges.append(newC) responses.append( self.__signum(sum(newC * self.orig_LTFArray.weight_array))) return model
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 = tools.all_inputs(n) weight_array = LTFArray.normal_weights( n, k, mu=mu, sigma=sigma, random_instance=RandomState(0xBADA556)) bias_value = 2.5 biased_ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=bias_value, ) ltf_array = LTFArray( weight_array=weight_array, transform=LTFArray.transform_id, combiner=LTFArray.combiner_xor, bias=None, ) # the second dimension of the weight_array must be the number of elements in biased weight_array self.assertEqual( shape(ltf_array.weight_array)[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 test. self.assertTrue(array(bias_array_compared).all()) biased_responses = biased_ltf_array.eval(challenges) responses = ltf_array.eval(challenges) self.assertFalse(array_equal(biased_responses, responses))
def run(self): """ Initializes the instance, the training set and the learner to then run the logistic regression with the given parameters. """ # TODO input transformation is computed twice. Add a shortcut to recycle results from the first computation self.instance = LTFArray( weight_array=LTFArray.normal_weights(self.n, self.k, random_instance=self.instance_prng), transform=self.transformation, combiner=self.combiner, ) self.learner = LogisticRegression( tools.TrainingSet(instance=self.instance, N=self.N, random_instance=self.challenge_prng), self.n, self.k, transformation=self.transformation, combiner=self.combiner, weights_prng=self.model_prng, logger=self.progress_logger, ) self.model = self.learner.learn()
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)) + '}')