Uniqueness

Uniqueness is a measure for how differently PUF instances of the same class behave. As security is build on the individual behavior, a high uniqueness is a minimum security requirement for any PUF. The concept of uniqueness is also often called inter-distance. pypuf can approximate the uniqueness based on given instances of Simulation or based on response data, see below.

Uniqueness is estimated on a per-challenge basis, as low uniqueness on a small number of challenges can be problematic. To obtain a general uniqueness measure for each response bit, average results along the first axis.

pypuf.metrics.uniqueness(instances: List[Simulation], seed: int, N: int = 10000) ndarray

Estimates the uniqueness of a list of given Simulations.

Randomly generates \(N\) challenges using seed \(\texttt{seed}\), then queries each simulation each challenge, obtaining an array with shape \((l, N, m)\) of all responses, where \(l\) is the number of simulations, and \(m\) is the response length of the given simulations. (All given simulations must have same challenge and response lenght.)

Then applies uniqueness_data() to determine the uniqueness of each response bit.

Returns a float-array of shape \((m,)\), giving the uniqueness of each output bit. To obtain total uniqueness, average along all axes, but be aware that low uniqueness on individual response bits may be problematic.

>>> from numpy import average
>>> from pypuf.simulation import XORArbiterPUF
>>> from pypuf.metrics import uniqueness
>>> instances = [XORArbiterPUF(n=64, k=1, seed=seed) for seed in range(5)]
>>> uniqueness(instances, seed=31415, N=1000)
array([0.924])
pypuf.metrics.uniqueness_data(responses: ndarray) ndarray

Estimates the uniqueness of responses of a set of PUF instances per challenge.

Given PUF responses in \(\{-1,1\}^m\) in an array of shape \((l, N, m)\), where \(l \in \mathbb{N}\) is the number of PUF instances, \(N \in \mathbb{N}\) is the number of challenges queried, and \(m \in \mathbb{N}\) is the response length, returns an estimate of the uniqueness of PUFs on challenges in this set, i.e. an approximation of

\[1 - 2 \cdot E_{f, g; f \neq g} \left[ \left| \frac{1}{2} - \Pr_x \left[ f(x) = g(x) \right] \right| \right]\]

where the challenges \(x\) are from the (implicitly) provided challenges, \(f(x)\) and \(g(x)\) are the responses of PUFs \(f\) and \(g\) described in the provided data.

For perfectly unique PUFs and for any \(f\) and \(g\), we expect \(\Pr_x \left[ f(x) = g(x) \right] = 1/2\), hence the uniqueness to be 1. On the other hand, if any two \(f\) and \(g\) have similarity higher (or lower) than \(1/2\), then the uniqueness will be lower than 1.

Returns an array of shape \((m,)\) with uniqueness values per response bit.

>>> from numpy import random, array
>>> from pypuf.metrics import uniqueness_data, similarity_data
>>> prng = random.default_rng(seed=1)
>>> # generate **different** random responses using numpy's pseudo-random generator
>>> responses = array([2 * random.default_rng(seed).integers(0, 2, size=(1000, 3)) - 1 for seed in range(4)])
>>> uniqueness_data(responses)
array([0.97333333, 0.979     , 0.971     ])
>>> # generate **same** random responses using numpy's pseudo-random generator
>>> responses = array([2 * random.default_rng(1).integers(0, 2, size=(1000, 1)) - 1 for seed in range(4)])
>>> uniqueness_data(responses)
array([0.])