Skip to content

Commit c23ba88

Browse files
nils-wisiolAdomas Baliuka
andcommitted
adds simulation, attack, and metrics related to optical PUFs
Co-Authored-By: Adomas Baliuka <[email protected]>
1 parent ed63388 commit c23ba88

File tree

15 files changed

+385
-8
lines changed

15 files changed

+385
-8
lines changed

CITATION.cff

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ authors:
2020
given-names: Niklas
2121
- family-names: Mursi
2222
given-names: Khalid T.
23+
- family-names: Baliuka
24+
given-names: Adomas
2325
license: GPL 3.0

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ To refer to pypuf, please use DOI `10.5281/zenodo.3901410`.
3939
pypuf is published [via Zenodo](https://zenodo.org/badge/latestdoi/87066421).
4040
Please cite this work as
4141

42-
> Nils Wisiol, Christoph Gräbnitz, Christopher Mühl, Benjamin Zengin, Tudor Soroceanu, Niklas Pirnay, & Khalid T. Mursi.
42+
> Nils Wisiol, Christoph Gräbnitz, Christopher Mühl, Benjamin Zengin, Tudor Soroceanu, Niklas Pirnay, Khalid T. Mursi,
43+
> & Adomas Baliuka.
4344
> pypuf: Cryptanalysis of Physically Unclonable Functions (Version 2, June 2021). Zenodo.
4445
> https://doi.org/10.5281/zenodo.3901410
4546
@@ -53,7 +54,8 @@ or use the following BibTeX:
5354
Benjamin Zengin and
5455
Tudor Soroceanu and
5556
Niklas Pirnay and
56-
Khalid T. Mursi},
57+
Khalid T. Mursi and
58+
Adomas Baliuka},
5759
title = {{pypuf: Cryptanalysis of Physically Unclonable
5860
Functions}},
5961
year = 2021,

docs/appendix/bibliography.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Bibliography
3636
.. [NSJM19] Nguyen, P. H. et al. The Interpose PUF: Secure PUF Design against State-of-the-art Machine Learning Attacks.
3737
IACR Transactions on Cryptographic Hardware and Embedded Systems 243–290 (2019) doi:10.13154/tches.v2019.i4.243-290.
3838
.. [ODon14] O’Donnell, R. Analysis of Boolean Functions. (Cambridge University Press, 2014).
39+
.. [RHUWDFJ13] Rührmair, U. et al. Optical PUFs Reloaded. https://eprint.iacr.org/2013/215 (2013).
3940
.. [RSSD10] Rührmair, U. et al. Modeling Attacks on Physical Unclonable Functions. in Proceedings of the 17th ACM
4041
Conference on Computer and Communications Security 237–249 (ACM, 2010). doi:10.1145/1866307.1866335.
4142
.. [SD07] Suh, G. E. & Devadas, S. Physical Unclonable Functions for Device Authentication and Secret Key Generation.

docs/attacks/linear_regression.rst

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
Linear Regression
2+
=================
3+
4+
Linear Regression fits a linear function on given data. The resulting linear function, also called map, is guaranteed
5+
to be optimal with respect to the total squared error, i.e. the sum of the squared differences of actual value and
6+
predicted value.
7+
8+
Linear Regression has many applications, in pypuf, it can be used to model :doc:`../simulation/optical` and
9+
:doc:`../simulation/arbiter_puf`.
10+
11+
12+
Arbiter PUF Reliability Side-Channel Attack [DV13]_
13+
---------------------------------------------------
14+
15+
For Arbiter PUFs, the reliability for any given challenge :math:`c` has a close relationship with the difference in
16+
delay for the top and bottom line. When modeling the Arbiter PUF response as
17+
18+
.. math::
19+
r = \text{sgn}\left[ D_\text{noise} + \langle w, x \rangle \right],
20+
21+
where :math:`x` is the feature vector corresponding to the challenge :math:`c` and :math:`w \in \mathbb{R}^n` are the
22+
weights describing the Arbiter PUF, and :math:`D_\text{noise}` is chosen from a Gaussian distribution with zero mean
23+
and variance :math:`\sigma_\text{noise}^2` to model the noise, then we can conclude that
24+
25+
.. math::
26+
\text{E}[r(x)] = \text{erf}\left( \frac{\langle w, x \rangle}{\sqrt{2}\sigma_\text{noise}} \right).
27+
28+
Hence, the delay difference :math:`\langle w, x \rangle` can be approximated based on an approximation of
29+
:math:`\text{E[r(x)]}`, which can be easily obtained by an attacker. It gives
30+
31+
.. math::
32+
\langle w, x \rangle = \sqrt{2}\sigma_\text{noise} \cdot \text{erf}^{-1} \text{E}[r(x)].
33+
34+
This approximation works well even when :math:`\text{E}[r(x)]` is approximated based on only on few responses, e.g. 3
35+
(see below).
36+
37+
To demonstrate the attack, we initialize an Arbiter PUF simulation with noisiness chosen such that the reliability
38+
will be about 91% *on average*:
39+
40+
>>> import pypuf.simulation, pypuf.io, pypuf.attack, pypuf.metrics
41+
>>> puf = pypuf.simulation.ArbiterPUF(n=64, noisiness=.25, seed=3)
42+
>>> pypuf.metrics.reliability(puf, seed=3).mean()
43+
0.908...
44+
45+
We then create a CRP set using the *average* value of responses to 500 challenges, based on 5 measurements:
46+
47+
>>> challenges = pypuf.io.random_inputs(n=puf.challenge_length, N=500, seed=2)
48+
>>> responses_mean = puf.r_eval(5, challenges).mean(axis=-1)
49+
>>> crps = pypuf.io.ChallengeResponseSet(challenges, responses_mean)
50+
51+
Based on these approximated values ``responses_mean`` of the linear function :math:`\langle w, x \rangle`, we use
52+
linear regression to find a linear mapping with small error to fit the data. Note that we use the ``transform_atf``
53+
function to compute the feature vector :math:`x` from the challenges :math:`c`, as the mapping is linear in :math:`x`
54+
(but not in :math:`c`).
55+
56+
>>> attack = pypuf.attack.LeastSquaresRegression(crps, feature_map=lambda cs: pypuf.simulation.ArbiterPUF.transform_atf(cs, k=1)[:, 0, :])
57+
>>> model = attack.fit()
58+
59+
The linear map ``model`` will predict the delay difference of a given challenge. To obtain the predicted PUF response,
60+
this prediction needs to be thresholded to either -1 or 1:
61+
62+
>>> model.postprocessing = model.postprocessing_threshold
63+
64+
To measure the resulting model accuracy, we use :meth:`pypuf.metrics.similarity`:
65+
66+
>>> pypuf.metrics.similarity(puf, model, seed=4)
67+
array([0.902])
68+
69+
70+
Modeling Attack on Integrated Optical PUFs [RHUWDFJ13]_
71+
-------------------------------------------------------
72+
73+
The behavior of an integrated optical PUF token can be understood as a linear map
74+
:math:`T \in \mathbb{C}^{n \times m}` of the given challenge, where the value of :math:`T` are determined by the given
75+
PUF token, and :math:`n` is number of challenge pixels, and :math:`m` the number of response pixels.
76+
The speckle pattern of the PUF is a measurement of the intensity of its electromagnetic field at the output, hence the
77+
intensity at a given response pixel :math:`r_i` for a given challenge :math:`c` can be written as
78+
79+
.. math::
80+
r_i = \left| c \cdot T \right|^2.
81+
82+
pypuf ships a basic simulator for the responses of :doc:`../simulation/optical`, on whose data a modeling attack
83+
can be demonstrated. We first initialize a simulation and collect challenge-response pairs:
84+
85+
>>> puf = pypuf.simulation.IntegratedOpticalPUF(n=64, m=25, seed=1)
86+
>>> crps = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=2)
87+
88+
Then, we fit a linear map on the data contained in ``crps``. Note that the simulation returns *intensity* values rather
89+
than *field* values. We thus need to account for quadratic terms using an appropriate
90+
:meth:`feature map <pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved>`.
91+
92+
>>> attack = pypuf.attack.LeastSquaresRegression(crps, feature_map=pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved)
93+
>>> model = attack.fit()
94+
95+
The success of the attack can be visually inspected or quantified by the :doc:`/metrics/correlation` of the response
96+
pixels:
97+
98+
>>> crps_test = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=3)
99+
>>> pypuf.metrics.correlation(model, crps_test).mean()
100+
0.69...
101+
102+
Note that the correlation can differ when additionally, post-processing of the responses is performed, e.g. by
103+
thresholding the values such that half the values give -1 and the other half 1:
104+
105+
>>> import numpy as np
106+
>>> threshold = lambda r: np.sign(r - np.quantile(r.flatten(), .5))
107+
>>> pypuf.metrics.correlation(model, crps_test, postprocessing=threshold).mean()
108+
0.41...
109+
110+
111+
API
112+
---
113+
114+
.. autoclass::
115+
pypuf.attack.LeastSquaresRegression
116+
:members: __init__, fit, model, feature_map_optical_pufs_reloaded, feature_map_optical_pufs_reloaded_improved

docs/index.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Some functionality is only implemented in the
1717
simulation/arbiter_puf
1818
simulation/delay
1919
simulation/bistable
20+
simulation/optical
2021
simulation/base
2122

2223
.. toctree::
@@ -36,6 +37,7 @@ Some functionality is only implemented in the
3637
metrics/reliability
3738
metrics/uniqueness
3839
metrics/distance
40+
metrics/correlation
3941
Fourier-Analysis (PUFMeter) <metrics/fourier>
4042

4143
.. toctree::
@@ -47,6 +49,7 @@ Some functionality is only implemented in the
4749
Logistic Regression <attacks/lr>
4850
Multilayer Perceptron <attacks/mlp>
4951
LMN (PUFMeter) <attacks/lmn>
52+
attacks/linear_regression
5053

5154
.. toctree::
5255
:maxdepth: 2
@@ -105,8 +108,8 @@ pypuf is published `via Zenodo <https://zenodo.org/badge/latestdoi/87066421>`_.
105108
Please cite this work as
106109

107110
Nils Wisiol, Christoph Gräbnitz, Christopher Mühl, Benjamin Zengin, Tudor Soroceanu,
108-
Niklas Pirnay, & Khalid T. Mursi.
109-
pypuf: Cryptanalysis of Physically Unclonable Functions (Version v2, March 2021). Zenodo.
111+
Niklas Pirnay, Khalid T. Mursi, & Adomas Baliuka.
112+
pypuf: Cryptanalysis of Physically Unclonable Functions (Version v2, August 2021). Zenodo.
110113
https://doi.org/10.5281/zenodo.3901410
111114

112115
or use the following BibTeX::
@@ -118,7 +121,8 @@ or use the following BibTeX::
118121
Benjamin Zengin and
119122
Tudor Soroceanu and
120123
Niklas Pirnay and
121-
Khalid T. Mursi},
124+
Khalid T. Mursi and
125+
Adomas Baliuka},
122126
title = {{pypuf: Cryptanalysis of Physically Unclonable
123127
Functions}},
124128
year = 2021,

docs/metrics/correlation.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Correlation
2+
-----------
3+
4+
The correlation metric is useful to judge the prediction accuracy when responses are non-binary, e.g. when studying
5+
:doc:`/simulation/optical`.
6+
7+
>>> import pypuf.simulation, pypuf.io, pypuf.attack, pypuf.metrics
8+
>>> puf = pypuf.simulation.IntegratedOpticalPUF(n=64, m=25, seed=1)
9+
>>> crps = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=2)
10+
>>> crps_test = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=3)
11+
>>> feature_map = pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved
12+
>>> model = pypuf.attack.LeastSquaresRegression(crps, feature_map=feature_map).fit()
13+
>>> pypuf.metrics.correlation(model, crps_test).mean()
14+
0.69...
15+
16+
Note that the correlation can differ when additionally, post-processing of the responses is performed, e.g. by
17+
thresholding the values such that half the values give -1 and the other half 1:
18+
19+
>>> import numpy as np
20+
>>> threshold = lambda r: np.sign(r - np.quantile(r.flatten(), .5))
21+
>>> pypuf.metrics.correlation(model, crps_test, postprocessing=threshold).mean()
22+
0.41...
23+
24+
.. automodule:: pypuf.metrics
25+
:members: correlation, correlation_data
26+
:noindex:

docs/simulation/optical.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Integrated Optical PUFs
2+
=======================
3+
4+
pypuf ships a very basic simulation of integrated optical PUFs [RHUWDFJ13]_.
5+
6+
.. autoclass::
7+
pypuf.simulation.IntegratedOpticalPUF
8+
:members: __init__, eval

docs/simulation/overview.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pypuf currently features simulation of the following strong PUFs:
1515
Lightweight Secure PUF [MKP08]_, Permutation PUF [WBMS19]_, and Interpose PUF [NSJM19]_.
1616
2. :doc:`Feed-Forward Arbiter PUFs <arbiter_puf>` and XORs thereof [GLCDD04]_.
1717
3. :doc:`PUF designs based on bistable rings <bistable>` [CCLSR11]_ [XRHB15]_.
18+
4. :doc:`Integrated Optical PUFs <optical>` [RHUWDFJ13]_.
1819

1920
Technicalities
2021
--------------

pypuf/attack/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
from .mlp2021 import MLPAttack2021
44

55
from .fourier import LMNAttack
6+
7+
from .linear_regression import LeastSquaresRegression

pypuf/attack/linear_regression.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from typing import Callable, Optional
2+
3+
import numpy as np
4+
5+
from .base import OfflineAttack
6+
from ..io import ChallengeResponseSet
7+
from ..simulation.base import Simulation
8+
9+
10+
class LinearMapSimulation(Simulation):
11+
12+
@staticmethod
13+
def postprocessing_id(responses: np.ndarray) -> np.ndarray:
14+
return responses
15+
16+
@staticmethod
17+
def postprocessing_threshold(responses: np.ndarray) -> np.ndarray:
18+
return np.sign(responses)
19+
20+
def __init__(self, linear_map: np.ndarray, challenge_length: int,
21+
feature_map: Optional[Callable[[np.ndarray], np.ndarray]] = None,
22+
postprocessing: Optional[Callable[[np.ndarray], np.ndarray]] = None) -> None:
23+
super().__init__()
24+
self.map = linear_map
25+
self._challenge_length = challenge_length
26+
self.feature_map = feature_map or (lambda x: x)
27+
self.postprocessing = postprocessing or self.postprocessing_id
28+
29+
@property
30+
def challenge_length(self) -> int:
31+
return self._challenge_length
32+
33+
@property
34+
def response_length(self) -> int:
35+
return self.map.shape[1]
36+
37+
def eval(self, challenges: np.ndarray) -> np.ndarray:
38+
return self.postprocessing(self.feature_map(challenges) @ self.map)
39+
40+
41+
class LeastSquaresRegression(OfflineAttack):
42+
43+
@staticmethod
44+
def feature_map_linear(challenges: np.ndarray) -> np.ndarray:
45+
return challenges
46+
47+
@staticmethod
48+
def feature_map_optical_pufs_reloaded(challenges: np.ndarray) -> np.ndarray:
49+
"""
50+
Computes features of an optical PUF token using all ordered pairs of challenge bits [RHUWDFJ13]_.
51+
An optical system may be linear in these features.
52+
53+
.. note::
54+
This representation is redundant since it treats ordered paris of challenge bits are distinct.
55+
Actually, only unordered pairs of bits should be treated as distinct. For applications, use
56+
the function :meth:`feature_map_optical_pufs_reloaded_improved
57+
<pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved>`,
58+
which achieves the same with half the number of features.
59+
60+
:param challenges: array of shape :math:`(N, n)` representing challenges to the optical PUF.
61+
:return: array of shape :math:`(N, n^2)`, which, for each challenge, contains the flattened dyadic product of
62+
the challenge with itself.
63+
"""
64+
beta = np.einsum("...i,...j->...ij", challenges, challenges)
65+
return beta.reshape(beta.shape[:-2] + (-1,))
66+
67+
@staticmethod
68+
def feature_map_optical_pufs_reloaded_improved(challenges: np.ndarray) -> np.ndarray:
69+
r"""
70+
Computes features of an optical PUF token using all unordered pairs of challenge bits [RHUWDFJ13]_.
71+
An optical system may be linear in these features.
72+
73+
:param challenges: 2d array of shape :math:`(N, n)` representing `N` challenges of length :math:`n`.
74+
:return: array of shape :math:`(N, \frac{n \cdot (n + 1)}{2})`. The result `return[i]` consists of all products
75+
of unordered pairs taken from `challenges[i]`, which has shape `(N,)`.
76+
77+
>>> import numpy as np
78+
>>> import pypuf.attack
79+
>>> challenges = np.array([[2, 3, 5], [1, 0, 1]]) # non-binary numbers for illustration only.
80+
>>> pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved(challenges)
81+
array([[ 4, 6, 10, 9, 15, 25],
82+
[ 1, 0, 1, 0, 0, 1]])
83+
"""
84+
n = challenges.shape[1]
85+
idx = np.triu_indices(n)
86+
return np.einsum("...i,...j->...ij", challenges, challenges)[:, idx[0], idx[1]]
87+
88+
def __init__(self, crps: ChallengeResponseSet,
89+
feature_map: Optional[Callable[[np.ndarray], np.ndarray]] = None) -> None:
90+
super().__init__(crps)
91+
self.crps = crps
92+
self.feature_map = feature_map or (lambda x: x)
93+
self._model = None
94+
95+
def fit(self) -> Simulation:
96+
features = self.feature_map(self.crps.challenges)
97+
# TODO warn if more than one measurement
98+
linear_map = np.linalg.pinv(features) @ self.crps.responses[:, :, 0]
99+
self._model = LinearMapSimulation(linear_map, self.crps.challenge_length, self.feature_map)
100+
return self.model
101+
102+
@property
103+
def model(self) -> Simulation:
104+
return self._model

0 commit comments

Comments
 (0)