Skip to content
Simulation and Learning of Physically Unclonable Functions
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
figures Introduces LTFArray and LR Attack benchmark Apr 4, 2019
pypuf Merge branch 'read_from_file' of into b… Apr 29, 2019
.gitignore add a log directory for test logs Jan 9, 2018
.pylintrc Remove some linter warnings that didn't make sense Feb 19, 2019
.travis.yml Bump travis to xenial Jan 25, 2019
LICENSE.txt Basic Tools for Simulation and Learning Apr 3, 2017 Implemented learning and testing using CRPs in file Apr 5, 2019
docker-compose.yml Adds pypuf Docker environment to avoid installation on host system Mar 6, 2019 moved to pycodestyle, fixed some style issues Jan 25, 2019 moved to pycodestyle, fixed some style issues Jan 25, 2019
matplotlibrc Continuation of experimenter runs, pandas.DataFrame results Mar 4, 2019
requirements.txt Benchmark for LTFArray evaluation Mar 6, 2019 Continuation of experimenter runs, pandas.DataFrame results Mar 4, 2019 moved to pycodestyle, fixed some style issues Jan 25, 2019 Enables plotting of results without running incomplete experiments Apr 1, 2019

pypuf: Python PUF Simulator and Learner Master Branch Build Status Indicator

Physically Unclonable Functions (PUFs) are of research interest in the field of lightweight and secure authentication. PUFs usually provide a challenge-response-interface. It is of fundamental importance to study the security of this interface. One way to study the security is per empirical study. (Remember though, that this can only prove insecurity of any given PUF.)

pypuf provides simulations and attacks on PUFs; it aims at helping to understand PUFs and attacks on them. It also provides some tools for running experiments with the simulations and attacks.

Technically, pypuf heavily relies on numpy. Some operations base on an additional module that has been written in C (see installation section below).

Studies and Results

pypuf has been used in the following projects:


Currently pypuf relies heavily on numpy and is tested for Python versions 3.6 and 3.7. Some operations also require the polymath package and/or the scipy package.

Recommended Installation

The recommended way to run pypuf is to use a virtual environment. It can be created using the following steps. Please make sure that virtualenv, python, the python development files, and a compiler toolchain are available on your system. (On Debian: apt install build-essential python3 python3-dev virtualenv.)

In your pypuf clone directory,

# create and enter virtual environment
virtualenv -p python3 env
source env/bin/activate

# upgrade pip
python3 -m pip install --upgrade pip

# install requirements (polymath needs c99)
CC="gcc -std=c99" pip3 install -r requirements.txt

Afterwards, confirm a correct setup by running the tests:

python3 -m unittest

If you encounter any trouble, please refer to our continuous integration at travis-ci to see a working example or raise an issue on GitHub.

Docker Installation

If you don't want to install any packages onto your system, you can use a docker container to run pypuf. To do so, please first install docker and docker-compose. Afterwards, pypuf studies can be run like this:

docker-compose run pypuf python3 -m study benchmark

Remember that changes to requirements.txt require to rebuild the docker image, using

docker-compose build pypuf

Lazy Installations

You can run pypuf installing numpy and scipy from your distribution's repository. This will prevent you from using any features that rely on polymath and is hence not recommended. It is an easier way however to get started quickly. After installing python3, numpy, and scipy run the example to make sure everything is setup okay. (Unit tests for features relying on polymath will fail in this scenario!)


pypuf mainly consists of three parts, simulation, learning and experimenting that will be elaborated below. The simulation module can simulate different types of Physically Unclonable Functions, currently mostly Arbiter-based constructions. The learner module contains a logistic regression learner that can be used for many attacks on Arbiter-based PUFs and some other learners. Finally, the experimenting part of pypuf contains the experiments module and the studies module that can run experiments and aggregate them into results, respectively.

Note that pypuf mostly uses the {-1,1} notation of bits, where True = -1 and False = +1 (that is, -1 corresponds to traditional "1" and +1 corresponds to traditional "0").


The simulation currently consists of a very broad class, the LTF Array Simulator. It can simulate an array of Linear Threshold Functions and hence simulate Arbiter PUFs, XOR Arbiter PUFs, Lightweight Secure PUFs, Majority Vote PUFs, and more custom designs. To that end, the input transformation can be chosen (e.g. as designed for the Lightweight Secure PUF) and the combiner function can be chosen (to generalize the usually used XOR function).
Another component of the simulation is the Fourier expansion of a Boolean function. It either can be evaluated returning a real value or boxed into the sign operator, returning -1 or +1.

Input Transformation

LTFArray currently defines a couple of input transformations. More input transformations can be added by implementing a function and provide the function as a constructor argument to LTFArray.

  • id: use the generated challenge directly as input to the LTF (note that this does not correspond to the physical implementation of Arbiter PUFs)
  • atf: use Arbiter Threshold Functions, that is, transform the challenges in a way such that we simulate physical implementations of Arbiter PUFs
  • lightweight_secure_original: input transformation as defined by Majzoobi et al. in Lightweight Secure PUFs
  • soelter_lightweight_secure: as defined by Majzoobi et al., but with a one-bit modification due to Sölter.
  • polynomial: challenges are interpreted as polynomials from GF(2^n). From the initial challenge c the i-th Arbiter chain gets the coefficients of the polynomial c^(i+1) as challenge. Only challenges with length 8, 16, 24, 32, 48, 64 are accepted.
  • permutation_atf: for each Arbiter chain first a pseudorandom permutation is applied and thereafter the ATF transform.
  • random: Each Arbiter chain gets a random challenge derived from the original challenge using a PRNG.

LTFArray also implements "input transformation generators" that can be used to combine existing input transformations into new ones.

  • generate_concatenated_transform(transform_1, nn, transform_2): the first nn bit will be transformed using transform_1, the rest will be transformed with transform_2.
  • generate_random_permutation_transform(seed, nn, kk, atf): each of the kk LTFs will be fed a random, but fixed permutation generated based on the given seed. If atf, then challenges will be ATF-transformed after permuting them.
  • generate_stacked_transform(transform_1, kk, transform_2): the first kk challenges will be transformed using transform_1, the rest will be transformed with transform_2.

Combiner Function

LTFArray currently provides the traditional XOR (that is, parity) as a combiner function, as well as the Inner Product Mod 2 function. Further combiner functions can be implemented as static functions in LTFArray, or anywhere else and given to the LTFArray constructor.


pypuf currently ships a logistic regression algorithm that was proposed to learn (XOR) Arbiter PUFs by Sölter and Rührmair et al, utilizing the RPROP backpropagation. Additionally pypuf aims for the provision of PAC learning algorithms, currently represented only by the Low Degree Algorithm introduced by Mansour.

Experiments and Studies

pypuf provides the experiments module to run experiments in a reproducible and convenient way. The module contains the the Experimenter, a manager class that can run a list of experiments in parallel, maintain the experiments' status and results and output the status of the experiment run. It is capable of storing results to disk and provides a callback function that will be called after each finished experiment. Results and partial results are available as a pandas DataFrame for easy analysis. The module also contains the Experiment base class that can be extended to create new experiments.

The studies module is designed to connect experiments with results. Each study inherits from the Study base class and defines a name, a list of experiments to be run and a way to analyze it. All studies can be run by calling the study module (defined in and providing the package name of the study as the first argument. To run the Logistic Regression Mini Batch study that analyzes the success rate of logistic regression attacks on XOR Arbiter PUFs while using or not using mini batches, use

python3 -m study lr_minibatch.success_rates

The result data will be saved to ./results/success_rate_results.csv (in pandas CSV format), the figures generated by the study will be saved to ./figures/lr-minibatch*.pdf.

To implement a study, please refer to the package documentation of studies.base.


Some of pypufs algorithms can run a quite long time. To make run times more comparable across platforms, pypuf includes a benchmark study that ships some results from different CPUs and Python versions on some basic pypuf operations. It can be run locally to compare against those numbers. To run the benchmark, use

python3 -m study benchmark

Results currently included in pypuf are shown below.


pypuf is primarily designed as an API. However, it provides a subset of its features as a command line interface.

Command Line Interface

sim_learn is a command line interface that simulates an LTF array and tries to learn it using logistic regression. For simulation and learning, a couple of parameters can be chosen on the command line. Start sim_learn without parameters to get detailed usage information.

mv_num_of_votes is a command line interface that allows to compute the minimum number of required votes in a Majority Vote XOR Arbiter PUF such that a certain stability is achieved. For details, please refer to Why Attackers Lose.

stability_calculation is a command line interface that allows to generate a stability histogram for a simulated PUF, i.e. to determine an approximation of how the probability to see the 'correct' answer is distributed among the challenge space. For details, please refer to Why Attackers Lose.

Example Usage

Example usage of sim_learn that simulates a 64 bit 2-xor Arbiter PUF and learns it to approx. 98% from 12000 challenge response pairs: python3 64 2 atf xor 12000 1 1 0xdead 0xbeef


pypuf's two most important interfaces are the Learner and the Simulation that can interact with each other.

Example Usage

This example creates a 64 bit 2-XOR XOR Arbiter PUF instance and a Logistic Regression learner learner_lr to learn it. After learning, the model's accuracy is tested and the result is printed.

To run, use python3

from pypuf import tools
from pypuf.learner.regression.logistic_regression import LogisticRegression
from pypuf.simulation.arbiter_based.ltfarray import LTFArray

# create a simulation with random (Gaussian) weights
# for 64-bit 2-XOR
instance = LTFArray(
    weight_array=LTFArray.normal_weights(n=64, k=2),

# create the learner
lr_learner = LogisticRegression(
    t_set=tools.TrainingSet(instance=instance, N=12000),

# 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)


All contributions receive warm welcome! To contribute, simply open an issue and/or pull request and maintain coding style. Please follow the coding standards within this project, that is, keep your code just like the code that is already there. Also, please don't forget to add tests for your code. We will only accept contributions under GNU GPLv3.

If you're using pypuf in your research, please let us know so we can link to your work here.

Contribution quick check list

  • Is your contribution GPLv3 compatible?
  • Update accordingly
  • Document new code, update code comments for changed code
  • Provide tests for your code (to run the tests locally, use python3 -m unittest)
  • Do not use numpy.random directly; always use an numpy.random.RandomState instance.


Significant contribution to this project are due to (in chronological order):

  • Nils Wisiol (
  • Christoph Graebnitz (
  • Christopher Mühl (
  • Benjamin Zengin (
You can’t perform that action at this time.