Example #1
0
def train(challenges, responses, t_pairs):
    try:
        with open('weights.txt', 'rb') as f:
            weights = np.load(f)
    except:
        print("[*] ENOWEIGHTS")

    # create instance frome same weights for accuracy calculation
    instance = LTFArray(
        weight_array=weights,
        transform=LTFArray.transform_atf,
        combiner=LTFArray.combiner_xor,
    )

    # train model from obtained CRPs
    training_set = tools.ChallengeResponseSet(challenges, responses)
    lr_learner = LogisticRegression(
        t_set=training_set,
        n=48,
        k=4,
        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)

    print('Learned a 48-bit 4-xor XOR Arbiter PUF from {} CRPs with accuracy {}'.format(t_pairs, accuracy))
    
    return model
Example #2
0
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
Example #3
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()
Example #4
0
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)
Example #5
0
 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,
     )
Example #6
0
 def prepare(self):
     super().prepare()
     self.learner = LogisticRegression(
         t_set=TrainingSet(instance=self.ltf_array, N=self.parameters.N),
         n=self.parameters.n,
         k=self.parameters.k,
         transformation=self.ltf_array.transform,
         combiner=self.ltf_array.combiner,
         convergence_decimals=100,  # never converge
         iteration_limit=20,
     )
Example #7
0
def main():
    """
    Learns and evaluates a PUF.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('n', type=uint, help='challenge bits')
    parser.add_argument('k', type=uint, help='number of arbiter chains')
    parser.add_argument('num_tr',
                        type=uint,
                        help='number of CRPs to use for training')
    parser.add_argument('num_te',
                        type=uint,
                        help='number of CRPs to use for testing')
    parser.add_argument('file', type=str, help='file to read CRPs from')
    parser.add_argument('-1',
                        '--11-notation',
                        dest='in_11_notation',
                        action='store_true',
                        default=False,
                        help='file is in -1,1 notation (default is 0,1)')
    args = parser.parse_args()

    # read pairs from file
    training_set = tools.parse_file(args.file, args.n, 1, args.num_tr,
                                    args.in_11_notation)
    testing_set = tools.parse_file(args.file, args.n, args.num_tr + 1,
                                   args.num_te, args.in_11_notation)

    # create the learner
    lr_learner = LogisticRegression(
        t_set=training_set,
        n=args.n,
        k=args.k,
        transformation=LTFArray.transform_atf,
        combiner=LTFArray.combiner_xor,
    )

    # learn and test the model
    model = lr_learner.learn()
    accuracy = 1 - tools.approx_dist_nonrandom(model, testing_set)

    # output the result
    print(
        'Learned a {}-bit {}-xor XOR Arbiter PUF from {} CRPs with accuracy {}'
        .format(args.n, args.k, args.num_tr, accuracy))
Example #8
0
 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()
Example #9
0
class LRBenchmarkExperiment(LTFBenchmarkExperiment):
    """
    Measures the time the logistic regression learner takes to learn a target.
    """
    def __init__(self, progress_log_prefix, parameters):
        super().__init__(progress_log_prefix, parameters)
        self.learner = None

    def prepare(self):
        super().prepare()
        self.learner = LogisticRegression(
            t_set=TrainingSet(instance=self.ltf_array, N=self.parameters.N),
            n=self.parameters.n,
            k=self.parameters.k,
            transformation=self.ltf_array.transform,
            combiner=self.ltf_array.combiner,
            convergence_decimals=100,  # never converge
            iteration_limit=20,
        )

    def run(self):
        self.learner.learn()
Example #10
0
def train():
    instance = LTFArray(
        weight_array=LTFArray.normal_weights(n=48, k=4),
        transform=LTFArray.transform_atf,
        combiner=LTFArray.combiner_xor,
    )

    N = 18000

    # learn and test the model
    lr_learner = LogisticRegression(
        t_set=tools.TrainingSet(instance=instance, N=N),
        n=48,
        k=4,
        transformation=LTFArray.transform_atf,
        combiner=LTFArray.combiner_xor,
    )

    model = lr_learner.learn()
    accuracy = 1 - tools.approx_dist(instance, model, 10000)

    print(
        'Learned a 48bit 4-xor XOR Arbiter PUF from %d CRPs with accuracy %f' %
        (N, accuracy))
Example #11
0
class CorrelationAttack(Learner):
    """
    Learn an LTF-Array that uses the transform_lightweight_secure.

    This Attack uses Logistic Regression (LR) to learn an initial model and subsequently exploits the correlation
    between the weight arrays to restart the LR learner on a permuted model. This leads to a
    faster retrieval of high-accuracy models than pure LR.
    """
    OPTIMIZATION_ACCURACY_LOWER_BOUND = .65
    OPTIMIZATION_ACCURACY_UPPER_BOUND = .95
    OPTIMIZATION_ACCURACY_GOAL = .98

    def __init__(self,
                 n,
                 k,
                 training_set,
                 validation_set,
                 weights_mu=0,
                 weights_sigma=1,
                 weights_prng=RandomState(),
                 lr_iteration_limit=1000,
                 mini_batch_size=0,
                 convergence_decimals=2,
                 shuffle=False,
                 logger=None):
        """
        Initialize a Correlation Attack Learner for the specified LTF Array which uses transform_lightweight_secure.

        :param n: Input length
        :param k: Number of parallel LTFs in the LTF Array
        :param training_set: The training set, i.e. a data structure containing challenge response pairs
        :param validation_set: The validation set, i.e. a data structure containing challenge response pairs. Used for
        approximating accuracies of permuted models (can be smaller e.g. 0.1*training_set_size)
        :param weights_mu: mean of the Gaussian that is used to choose the initial model
        :param weights_sigma: standard deviation of the Gaussian that is used to choose the initial model
        :param weights_prng: PRNG to draw the initial model from. Defaults to fresh `numpy.random.RandomState` instance.
        :param lr_iteration_limit: Iteration limit for a single LR learner run
        :param logger: logging.Logger
                       Logger which is used to log detailed information of learn iterations.
        """
        self.n = n
        self.k = k

        self.validation_set_efba = ChallengeResponseSet(
            challenges=LTFArray.efba_bit(
                LTFArray.transform_lightweight_secure(
                    validation_set.challenges, k)),
            responses=validation_set.responses)

        self.logger = logger

        self.lr_learner = LogisticRegression(
            t_set=training_set,
            n=n,
            k=k,
            transformation=LTFArray.transform_lightweight_secure,
            combiner=LTFArray.combiner_xor,
            weights_mu=weights_mu,
            weights_sigma=weights_sigma,
            weights_prng=weights_prng,
            logger=logger,
            iteration_limit=lr_iteration_limit,
            minibatch_size=mini_batch_size,
            convergence_decimals=convergence_decimals,
            shuffle=shuffle)

        self.initial_accuracy = .5
        self.initial_lr_iterations = 0
        self.initial_model = None
        self.total_lr_iterations = 0
        self.best_permutation_iteration = 0
        self.total_permutation_iterations = 0
        self.best_permutation = None
        self.best_accuracy = None

        assert n in (
            64, 128
        ), 'Correlation attack for %i bit is currently not supported.' % n
        assert validation_set.N >= 1000, 'Validation set should contain at least 1000 challenges.'

        self.correlation_permutations = loadmat(
            'data/correlation_permutations_lightweight_secure_%i_10.mat' %
            n)['shiftOverviewData'][:, :, 0].astype('int64')

    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.
        """
        self.initial_model = initial_model = self.lr_learner.learn()
        self.logger.debug('initial weights for corr attack:')
        self.logger.debug(','.join(
            map(str, initial_model.weight_array.flatten())))
        self.initial_accuracy = self.approx_accuracy(
            initial_model, self.validation_set_efba.block_subset(0, 2))
        self.initial_lr_iterations = self.lr_learner.iteration_count
        self.total_lr_iterations = self.initial_lr_iterations
        initial_updater = self.lr_learner.updater

        self.best_accuracy = self.initial_accuracy

        self.logger.debug('Initial accuracy is %.4f' % self.initial_accuracy)

        if self.initial_accuracy < self.OPTIMIZATION_ACCURACY_LOWER_BOUND:
            self.logger.debug('initial learning below threshold, aborting')
            return initial_model

        if self.initial_accuracy > self.OPTIMIZATION_ACCURACY_GOAL:
            self.logger.debug('initial learning successful, aborting')
            return initial_model

        # Try all permutations with high initial accuracy and see if any of them lead to a good final result
        high_accuracy_permutations = self.find_high_accuracy_weight_permutations(
            initial_model.weight_array,
            # allow some accuracy loss by permuting
            # the higher the initial accuracy, the higher the loss we allow
            # result will never be below 0.925
            1.2 * self.best_accuracy - .2)

        best_model = initial_model
        self.logger.debug('Trying %i permuted weights.' %
                          len(high_accuracy_permutations))
        for (iteration, perm_data) in enumerate(high_accuracy_permutations):
            self.total_permutation_iterations += 1
            weights = self.adopt_weights(initial_model.weight_array,
                                         perm_data.permutation)
            self.lr_learner.updater = deepcopy(initial_updater)
            self.lr_learner.updater.step_size *= 10
            model = self.lr_learner.learn(init_weight_array=weights,
                                          refresh_updater=False)
            self.total_lr_iterations += self.lr_learner.iteration_count
            accuracy = self.approx_accuracy(
                model, self.validation_set_efba.block_subset(1, 2))
            self.logger.debug(
                'With permutation no %d=%s, after restarting the learning we achieved accuracy %.4f -> %.4f!'
                % (iteration, perm_data.permutation, perm_data.accuracy,
                   accuracy))
            if accuracy > 0.1 + 0.9 * self.initial_accuracy \
                    and accuracy > self.best_accuracy:
                # demand some "substantial" improvement of accuracy
                # what substantial means becomes weaker as we approach
                # perfect accuracy
                best_model = model
                self.best_accuracy = accuracy
                self.best_permutation_iteration = iteration + 1
                self.best_permutation = perm_data.permutation
            else:
                self.logger.debug(
                    'Learning after permuting lead to accuracy %.2f, no improvement :-('
                    % accuracy)

            if accuracy > self.OPTIMIZATION_ACCURACY_GOAL:
                self.logger.debug(
                    'Found a model with accuracy better than %.2f. Terminating'
                    % self.OPTIMIZATION_ACCURACY_GOAL)
                return model

        self.logger.debug(
            'After trying all permutations, we found a model with acc. %.2f.' %
            self.best_accuracy)
        return best_model

    def find_high_accuracy_weight_permutations(self, weights, threshold):
        """
        Gives permutations for the weight-array resulting in the highest model accuracies.
        :param weights: The original weight-array
        :param threshold: Minimum accuracy to consider
        :return: The 5k permutations with the highest accuracy
        """
        high_accuracy_permutations = []
        adopted_instance = LTFArray(
            weight_array=zeros((self.k, self.n)),
            transform=LTFArray.transform_lightweight_secure,
            combiner=LTFArray.combiner_xor)
        for permutation in list(permutations(range(self.k)))[1:]:
            adopted_instance.weight_array = self.adopt_weights(
                weights, permutation)
            accuracy = self.approx_accuracy(adopted_instance)
            self.logger.debug('For permutation %s, we have accuracy %.4f' %
                              (permutation, accuracy))
            if accuracy >= threshold:
                high_accuracy_permutations.append(
                    PermData(permutation, accuracy))

        high_accuracy_permutations.sort(key=lambda x: -x.accuracy)
        return high_accuracy_permutations[:5 * self.k]

    def approx_accuracy(self, instance, efba_set=None):
        """
        Approximate the accuracy of the instance on the given set.
        :param instance: pypuf.simulation.arbiter_based.LTFArray
        :param efba_set: A challenge-response-set containing efba sub-challenges (default: self.validation_set_efba)
        :return: Accuracy of the instance
        """
        if efba_set is None:
            efba_set = self.validation_set_efba
        size = efba_set.N
        responses = sign(
            instance.combiner(instance.core_eval(efba_set.challenges)))
        return count_nonzero(responses == efba_set.responses) / size

    def adopt_weights(self, weights, permutation):
        """
        Adopts the weights with the given permutation exploiting the correlations of the lightweight-secure transform.
        :param weights: A weight-array of an LTFArray
        :param permutation: Permutation as returned from itertools.permutations
        :return: Permuted weight-array
        """
        adopted_weights = empty(weights.shape)
        for l in range(self.k):
            adopted_weights[permutation[l], :] = \
                roll(weights[l, :], self.correlation_permutations[l, permutation[l]])
        return adopted_weights
Example #12
0
)

train_set = tools.TrainingSet(instance=instance, N=15000)
val_set = train_set.subset(slice(10000, None))
train_set = train_set.subset(slice(None, 10000))

challenges, responses = train_set.challenges, train_set.responses

print(challenges.shape, responses.shape)

from pypuf.learner.regression.logistic_regression import LogisticRegression

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)
acc = accuracy_score(val_set_predicted_responses, val_set.responses)

print('accuracy: ', acc)

from pypuf.learner.other import Boosting

boosting_learner = Boosting(
    t_set=train_set,
Example #13
0
class ExperimentLogisticRegression(Experiment):
    """
    This Experiment uses the logistic regression learner on an LTFArray PUF simulation.
    """
    def __init__(self, progress_log_prefix, parameters):
        progress_log_name = None if progress_log_prefix is None else '%s.0x%x_0x%x_0_%i_%i_%i_%s_%s' % (
            progress_log_prefix,
            parameters.seed_model,
            parameters.seed_instance,
            parameters.n,
            parameters.k,
            parameters.N,
            parameters.transformation,
            parameters.combiner,
        )
        super().__init__(progress_log_name, parameters)
        self.instance = None
        self.learner = None
        self.model = None

    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 run(self):
        """
        Runs the learner
        """
        self.model = self.learner.learn()

    def analyze(self):
        """
        Analyzes the learned result.
        """
        assert self.model is not None
        accuracy = 1.0 - tools.approx_dist(
            self.instance,
            self.model,
            min(10000, 2**self.parameters.n),
            random_instance=RandomState(self.parameters.seed_distance),
        )

        return Result(
            experiment_id=self.id,
            pid=getpid(),
            iteration_count=self.learner.iteration_count,
            epoch_count=self.learner.epoch_count,
            gradient_step_count=self.learner.gradient_step_count,
            measured_time=self.measured_time,
            accuracy=accuracy,
            model=self.model.weight_array.flatten() /
            norm(self.model.weight_array.flatten()),
        )
Example #14
0
    
    if algorithm==2:
        learner = PolytopeAlgorithm(
                instance,
                tools.TrainingSet(instance=instance, N=N),
                n,
                k,
                transformation=transformation,
                combiner=combiner,
                weights_prng=model_prng,
                )
    else:
        learner = LogisticRegression(
                tools.TrainingSet(instance=instance, N=N),
                n,
                k,
                transformation=transformation,
                combiner=combiner,
                weights_prng=model_prng,
                )

    i = 0
    dist = 1

    while i < restarts and 1 - dist < convergence:
        stderr.write('\r%5i/%5i         ' % (i+1, restarts if restarts < float('inf') else 0))
        start = time.time()
        model = learner.learn()
        end = time.time()
        training_times = append(training_times, end - start)
        dist = tools.approx_dist(instance, model, min(10000, 2 ** n))
        accuracy = append(accuracy, 1 - dist)
Example #15
0
    def __init__(self,
                 n,
                 k,
                 training_set,
                 validation_set,
                 weights_mu=0,
                 weights_sigma=1,
                 weights_prng=RandomState(),
                 lr_iteration_limit=1000,
                 mini_batch_size=0,
                 convergence_decimals=2,
                 shuffle=False,
                 logger=None):
        """
        Initialize a Correlation Attack Learner for the specified LTF Array which uses transform_lightweight_secure.

        :param n: Input length
        :param k: Number of parallel LTFs in the LTF Array
        :param training_set: The training set, i.e. a data structure containing challenge response pairs
        :param validation_set: The validation set, i.e. a data structure containing challenge response pairs. Used for
        approximating accuracies of permuted models (can be smaller e.g. 0.1*training_set_size)
        :param weights_mu: mean of the Gaussian that is used to choose the initial model
        :param weights_sigma: standard deviation of the Gaussian that is used to choose the initial model
        :param weights_prng: PRNG to draw the initial model from. Defaults to fresh `numpy.random.RandomState` instance.
        :param lr_iteration_limit: Iteration limit for a single LR learner run
        :param logger: logging.Logger
                       Logger which is used to log detailed information of learn iterations.
        """
        self.n = n
        self.k = k

        self.validation_set_efba = ChallengeResponseSet(
            challenges=LTFArray.efba_bit(
                LTFArray.transform_lightweight_secure(
                    validation_set.challenges, k)),
            responses=validation_set.responses)

        self.logger = logger

        self.lr_learner = LogisticRegression(
            t_set=training_set,
            n=n,
            k=k,
            transformation=LTFArray.transform_lightweight_secure,
            combiner=LTFArray.combiner_xor,
            weights_mu=weights_mu,
            weights_sigma=weights_sigma,
            weights_prng=weights_prng,
            logger=logger,
            iteration_limit=lr_iteration_limit,
            minibatch_size=mini_batch_size,
            convergence_decimals=convergence_decimals,
            shuffle=shuffle)

        self.initial_accuracy = .5
        self.initial_lr_iterations = 0
        self.initial_model = None
        self.total_lr_iterations = 0
        self.best_permutation_iteration = 0
        self.total_permutation_iterations = 0
        self.best_permutation = None
        self.best_accuracy = None

        assert n in (
            64, 128
        ), 'Correlation attack for %i bit is currently not supported.' % n
        assert validation_set.N >= 1000, 'Validation set should contain at least 1000 challenges.'

        self.correlation_permutations = loadmat(
            'data/correlation_permutations_lightweight_secure_%i_10.mat' %
            n)['shiftOverviewData'][:, :, 0].astype('int64')
Example #16
0
class ExperimentLogisticRegression(Experiment):
    """
        This Experiment uses the logistic regression learner on an LTFArray PUF simulation.
    """
    def __init__(self, log_name, n, k, N, seed_instance, seed_model,
                 transformation, combiner):
        super().__init__(log_name='%s.0x%x_0x%x_0_%i_%i_%i_%s_%s' % (
            log_name,
            seed_model,
            seed_instance,
            n,
            k,
            N,
            transformation.__name__,
            combiner.__name__,
        ), )
        self.n = n
        self.k = k
        self.N = N
        self.seed_instance = seed_instance
        self.instance_prng = RandomState(seed=self.seed_instance)
        self.seed_model = seed_model
        self.model_prng = RandomState(seed=self.seed_model)
        self.combiner = combiner
        self.transformation = transformation
        self.instance = None
        self.learner = None
        self.model = None

    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),
            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 analyze(self):
        """
        Analyzes the learned result.
        """
        assert self.model is not None

        self.result_logger.info(
            # seed_instance  seed_model i      n      k      N      trans  comb   iter   time   accuracy  model values
            '0x%x\t'
            '0x%x\t'
            '%i\t'
            '%i\t'
            '%i\t'
            '%i\t'
            '%s\t'
            '%s\t'
            '%i\t'
            '%f\t'
            '%f\t'
            '%s' % (
                self.seed_instance,
                self.seed_model,
                0,  # restart count, kept for compatibility to old log files
                self.n,
                self.k,
                self.N,
                self.transformation.__name__,
                self.combiner.__name__,
                self.learner.iteration_count,
                self.measured_time,
                1.0 - tools.approx_dist(self.instance, self.model,
                                        min(10000, 2**self.n)),
                ','.join(
                    map(
                        str,
                        self.model.weight_array.flatten() /
                        norm(self.model.weight_array.flatten())))))
Example #17
0
class ExperimentLogisticRegression(Experiment):
    """
    This Experiment uses the logistic regression learner on an LTFArray PUF simulation.
    """

    def __init__(
            self, log_name, n, k, N, seed_instance, seed_model, transformation, combiner, seed_challenge=0x5A551,
            seed_chl_distance=0xB055,
    ):
        """
        :param log_name: string
                         Prefix of the path or name of the experiment log file.
        :param n: int
                  Number of stages of the PUF
        :param k: int
                  Number different LTFArrays
        :param N: int
                  Number of challenges which are generated in order to learn the PUF simulation.
        :param seed_instance: 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 seed_model: int
                           The seed which is used to initialize the pseudo-random number generator
                           which is used to generate the stage weights for the learner arbiter PUF simulation.
        :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 seed_challenge: int default is 0x5A551
                               The seed which is used to initialize the pseudo-random number generator
                               which is used to draft challenges for the TrainingSet.
        :param seed_chl_distance: int default is 0xB055
                                  The seed which is used to initialize the pseudo-random number generator
                                  which is used to draft challenges for the accuracy calculation.
        """
        super().__init__(
            log_name='%s.0x%x_0x%x_0_%i_%i_%i_%s_%s' % (
                log_name,
                seed_model,
                seed_instance,
                n,
                k,
                N,
                transformation.__name__,
                combiner.__name__,
            ),
        )
        self.n = n
        self.k = k
        self.N = N
        self.seed_instance = seed_instance
        self.instance_prng = RandomState(seed=self.seed_instance)
        self.seed_model = seed_model
        self.model_prng = RandomState(seed=self.seed_model)
        self.combiner = combiner
        self.transformation = transformation
        self.seed_challenge = seed_challenge
        self.challenge_prng = RandomState(self.seed_challenge)
        self.seed_chl_distance = seed_chl_distance
        self.distance_prng = RandomState(self.seed_chl_distance)
        self.instance = None
        self.learner = None
        self.model = None

    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 analyze(self):
        """
        Analyzes the learned result.
        """
        assert self.model is not None

        self.result_logger.info(
            # seed_instance  seed_model i      n      k      N      trans  comb   iter   time   accuracy  model values
            '0x%x\t'        '0x%x\t'   '%i\t' '%i\t' '%i\t' '%i\t' '%s\t' '%s\t' '%i\t' '%f\t' '%f\t'    '%s',
            self.seed_instance,
            self.seed_model,
            0,  # restart count, kept for compatibility to old log files
            self.n,
            self.k,
            self.N,
            self.transformation.__name__,
            self.combiner.__name__,
            self.learner.iteration_count,
            self.measured_time,
            1.0 - tools.approx_dist(
                self.instance,
                self.model,
                min(10000, 2 ** self.n),
                random_instance=self.distance_prng,
            ),
            ','.join(map(str, self.model.weight_array.flatten() / norm(self.model.weight_array.flatten())))

        )
Example #18
0
def main(args):

    if len(args) != 10:
        stderr.write('LTF Array Simulator and Logistic Regression Learner\n')
        stderr.write('Usage:\n')
        stderr.write(
            'sim_learn.py n k transformation combiner N restarts seed_instance seed_model\n'
        )
        stderr.write('               n: number of bits per Arbiter chain\n')
        stderr.write('               k: number of Arbiter chains\n')
        stderr.write(
            '  transformation: used to transform input before it is used in LTFs\n'
        )
        stderr.write('                  currently available:\n')
        stderr.write('                  - id  -- does nothing at all\n')
        stderr.write(
            '                  - atf -- convert according to "natural" Arbiter chain\n'
        )
        stderr.write('                           implementation\n')
        stderr.write(
            '                  - mm  -- designed to achieve maximum PTF expansion length\n'
        )
        stderr.write(
            '                           only implemented for k=2 and even n\n')
        stderr.write(
            '                  - lightweight_secure -- design by Majzoobi et al. 2008\n'
        )
        stderr.write(
            '                                          only implemented for even n\n'
        )
        stderr.write(
            '                  - shift_lightweight_secure -- design like Majzoobi\n'
        )
        stderr.write(
            '                                                et al. 2008, but with the shift\n'
        )
        stderr.write(
            '                                                operation executed first\n'
        )
        stderr.write(
            '                                                only implemented for even n\n'
        )
        stderr.write(
            '                  - soelter_lightweight_secure -- design like Majzoobi\n'
        )
        stderr.write(
            '                                                  et al. 2008, but one bit different\n'
        )
        stderr.write(
            '                                                  only implemented for even n\n'
        )
        stderr.write(
            '                  - 1_n_bent -- one LTF gets "bent" input, the others id\n'
        )
        stderr.write(
            '                  - 1_1_bent -- one bit gets "bent" input, the others id,\n'
        )
        stderr.write(
            '                                this is proven to have maximum PTF\n'
        )
        stderr.write('                                length for the model\n')
        stderr.write(
            '                  - polynomial -- challenges are interpreted as polynomials\n'
        )
        stderr.write(
            '                                  from GF(2^64). From the initial challenge c,\n'
        )
        stderr.write(
            '                                  the i-th Arbiter chain gets the coefficients \n'
        )
        stderr.write(
            '                                  of the polynomial c^(i+1) as challenge.\n'
        )
        stderr.write(
            '                                  For now only challenges with length n=64 are accepted.\n'
        )
        stderr.write(
            '                  - permutation_atf -- for each Arbiter chain first a pseudorandom permutation \n'
        )
        stderr.write(
            '                                       is applied and thereafter the ATF transform.\n'
        )
        stderr.write(
            '                  - random -- Each Arbiter chain gets a random challenge derived from the\n'
        )
        stderr.write(
            '                              original challenge using a PRNG.\n')
        stderr.write(
            '        combiner: used to combine the output bits to a single bit\n'
        )
        stderr.write('                  currently available:\n')
        stderr.write(
            '                  - xor     -- output the parity of all output bits\n'
        )
        stderr.write(
            '                  - ip_mod2 -- output the inner product mod 2 of all output\n'
        )
        stderr.write('                               bits (even n only)\n')
        stderr.write(
            '               N: number of challenge response pairs in the training set\n'
        )
        stderr.write(
            '        restarts: number of repeated initializations the learner\n'
        )
        stderr.write(
            '                  use float number x, 0<x<1 to repeat until given accuracy\n'
        )
        stderr.write(
            '       instances: number of repeated initializations the instance\n'
        )
        stderr.write(
            '                  The number total learning attempts is restarts*instances.\n'
        )
        stderr.write(
            '   seed_instance: random seed used for LTF array instance\n')
        stderr.write(
            '      seed_model: random seed used for the model in first learning attempt\n'
        )
        quit(1)

    n = int(args[1])
    k = int(args[2])
    transformation_name = args[3]
    combiner_name = args[4]
    N = int(args[5])

    if float(args[6]) < 1:
        restarts = float('inf')
        convergence = float(args[6])
    else:
        restarts = int(args[6])
        convergence = 1.1

    instances = int(args[7])

    seed_instance = int(args[8], 16)
    seed_model = int(args[9], 16)

    # reproduce 'random' numbers and avoid interference with other random numbers drawn
    instance_prng = RandomState(seed=seed_instance)
    model_prng = RandomState(seed=seed_model)

    transformation = None
    combiner = None

    try:
        transformation = getattr(LTFArray,
                                 'transform_%s' % transformation_name)
    except AttributeError:
        stderr.write(
            'Transformation %s unknown or currently not implemented\n' %
            transformation_name)
        quit()

    try:
        combiner = getattr(LTFArray, 'combiner_%s' % combiner_name)
    except AttributeError:
        stderr.write('Combiner %s unknown or currently not implemented\n' %
                     combiner_name)
        quit()

    stderr.write(
        'Learning %s-bit %s XOR Arbiter PUF with %s CRPs and %s restarts.\n\n'
        % (n, k, N, restarts))
    stderr.write('Using\n')
    stderr.write('  transformation:       %s\n' % transformation)
    stderr.write('  combiner:             %s\n' % combiner)
    stderr.write('  instance random seed: 0x%x\n' % seed_instance)
    stderr.write('  model random seed:    0x%x\n' % seed_model)
    stderr.write('\n')

    accuracy = array([])
    training_times = array([])
    iterations = array([])

    for j in range(instances):

        stderr.write('----------- Choosing new instance. ---------\n')

        instance = LTFArray(
            weight_array=LTFArray.normal_weights(
                n, k, random_instance=instance_prng),
            transform=transformation,
            combiner=combiner,
        )

        lr_learner = LogisticRegression(
            tools.TrainingSet(instance=instance, N=N),
            n,
            k,
            transformation=transformation,
            combiner=combiner,
            weights_prng=model_prng,
        )

        i = 0
        dist = 1

        while i < restarts and 1 - dist < convergence:
            stderr.write('\r%5i/%5i         ' %
                         (i + 1, restarts if restarts < float('inf') else 0))
            start = time.time()
            model = lr_learner.learn()
            end = time.time()
            training_times = append(training_times, end - start)
            dist = tools.approx_dist(instance, model, min(10000, 2**n))
            accuracy = append(accuracy, 1 - dist)
            iterations = append(iterations, lr_learner.iteration_count)
            # output test result in machine-friendly format
            # seed_ltf seed_model idx_restart n k N transformation combiner iteration_count time accuracy
            stderr.write(' '.join([
                '0x%x' % seed_instance,
                '0x%x' % seed_model,
                '%5d' % i,
                '%3d' % n,
                '%2d' % k,
                '%6d' % N,
                '%s' % transformation_name,
                '%s' % combiner_name,
                '%4d' % lr_learner.iteration_count,
                '%9.3f' % (end - start),
                '%1.5f' % (1 - dist),
            ]) + '\n')
            #stderr.write('training time:                % 5.3fs' % (end - start))
            #stderr.write('min training distance:        % 5.3f' % lr_learner.min_distance)
            #stderr.write('test distance (1000 samples): % 5.3f\n' % dist)
            i += 1

    stderr.write('\r              \r')
    stderr.write('\n\n')
    stderr.write('training times: %s\n' % training_times)
    stderr.write('iterations: %s\n' % iterations)
    stderr.write('test accuracy: %s\n' % accuracy)
    stderr.write('\n\n')
    stderr.write(
        'min/avg/max training time  : % 9.3fs /% 9.3fs /% 9.3fs\n' %
        (amin(training_times), mean(training_times), amax(training_times)))
    stderr.write('min/avg/max iteration count: % 9.3f  /% 9.3f  /% 9.3f \n' %
                 (amin(iterations), mean(iterations), amax(iterations)))
    stderr.write('min/avg/max test accuracy  : % 9.3f  /% 9.3f  /% 9.3f \n' %
                 (amin(accuracy), mean(accuracy), amax(accuracy)))
    stderr.write('\n\n')