All posts
Research

How a PUF works, from silicon variation to a login protocol

Physical unclonable functions turn manufacturing randomness into a fingerprint no one can copy. Here is how they are built, measured, made reliable and attacked, with simulations you can run.

, 8 min read

Every connected device has to answer one question before anything else: are you really who you say you are? The usual answer is a secret key stored in flash or fuses. That works until someone opens the package. Stored keys can be read with a probe station, a laser, a power trace or a firmware bug, and once a key is copied, a cheap clone is indistinguishable from the real device.

A physical unclonable function (PUF) removes the stored key. Instead of remembering a secret, the chip re-measures one from its own physical structure every time it needs it. Nobody, not even the manufacturer, can choose that secret or build a second chip with the same one.

This post walks through how that works, from the transistor level to a complete authentication protocol, and ends with the attacks that make PUF design hard.

The idea in one sentence

A PUF is a circuit that maps a challenge cc to a response rr, where the mapping depends on tiny, uncontrollable manufacturing differences:

r=fchip(c)r = f_{\text{chip}}(c)

Two chips built from the same layout file implement two different functions fAf_A and fBf_B. A pair (c,r)(c, r) is called a challenge–response pair (CRP).

PUFs come in two families:

FamilyChallengesTypical useExamples
Weak PUFFew or oneGenerate one device key on chipSRAM PUF, butterfly PUF
Strong PUFExponentially manyChallenge–response authenticationArbiter PUF, XOR arbiter PUF

Where the randomness comes from

No two transistors are identical. During fabrication, the number and position of dopant atoms in a channel, the roughness of etched line edges and the thickness of the gate oxide all vary at the atomic scale. The result is that every transistor has a slightly different threshold voltage and every wire a slightly different delay.

Chip designers normally fight this variation. A PUF designer amplifies it, by building circuits where two nominally identical parts compete and the winner is decided only by variation.

Design 1: the arbiter PUF

The arbiter PUF is the classic strong PUF. A single rising edge is sent down two paths through a chain of nn switch stages. Each stage either passes the two signals straight through or swaps them, depending on one challenge bit. At the end, an arbiter (a latch) records which signal arrived first.

Scroll sideways to see the whole diagram.

How an arbiter PUF races two signalsOne rising edge splits into a top and a bottom path. Each stage either passes the two paths straight or swaps them, depending on one challenge bit. An arbiter at the end outputs 1 if the top signal arrives first and 0 otherwise.…rPulseone rising edgeSTAGE 1c = 0paths straightSTAGE 2c = 1paths swapSTAGE nc = 1paths swapArbiterwho won?r = 1 if toparrives firstTOPBOTTOM
Same design, different winner. Every switch adds a delay that differs by picoseconds from chip to chip. The challenge bits choose which delays each signal collects, so the arbiter's verdict depends on both the challenge and the chip's physical variation.

Because the delay differences add up stage by stage, the arbiter PUF has a neat mathematical description called the additive delay model. The final delay difference is a weighted sum:

Δ(c)=w⊤ϕ(c),ϕi(c)=∏j=in(1−2cj),r={1Δ(c)>00otherwise\Delta(c) = \mathbf{w}^\top \boldsymbol{\phi}(c), \qquad \phi_i(c) = \prod_{j=i}^{n} (1 - 2c_j), \qquad r = \begin{cases} 1 & \Delta(c) > 0 \\ 0 & \text{otherwise} \end{cases}

The weight vector w\mathbf{w} holds the chip’s physical delay differences. It is different on every chip and never leaves the silicon. The feature vector ϕ(c)\boldsymbol{\phi}(c) is a fixed transformation of the challenge, the same for every chip. Keep this linear form in mind; it comes back when we discuss attacks.

Design 2: memory-based PUFs

Some PUFs need no special circuit at all. An SRAM cell is two cross-coupled inverters. When power is applied, both start at zero and race; the stronger inverter wins and the cell settles to 0 or 1. Most cells have a strong preference set by transistor mismatch, so the power-up pattern of a memory block is a fingerprint.

Scroll sideways to see the whole diagram.

SRAM power-up states as fingerprintsChip A powers up to almost the same pattern twice, with 3 of 64 cells flipping because of noise, while chip B's pattern differs from chip A in 33 of 64 cells.Chip A, power-up 1reference fingerprintChip A, power-up 23 of 64 bits flippedChip B, power-up33 of 64 bits differ from Acell wakes up as 1cell wakes up as 0
No extra circuit needed. Each SRAM cell is two cross-coupled inverters. At power-up, tiny transistor mismatches tip each cell to 0 or 1, the same way on most boots, but differently on every chip.

SRAM PUFs are popular because almost every microcontroller already has SRAM, so a fingerprint can be read in firmware before the memory is initialised. Their limitation is that they are weak PUFs: one block gives one fingerprint, so they are used to derive a key, not to answer millions of challenges.

Other common designs:

DesignWhat competesStrengthsWatch out for
Arbiter PUFTwo delay pathsHuge challenge space, tiny areaEasy to model with machine learning
XOR arbiter PUFk arbiter chains, outputs XOR-edMuch harder to modelNoise grows with k
Ring-oscillator PUFFrequencies of two ring oscillatorsSimple on FPGAsTemperature drift, more power
SRAM PUFTwo inverters in each cellNo extra hardwareAgeing, needs power cycle
Butterfly PUFCross-coupled latchesSRAM-like on FPGAsLayout must be symmetric

How good is a PUF? Four numbers

A PUF is only useful if it is different across chips and stable within a chip. Both are measured with the fractional Hamming distance HD(R1,R2)\mathrm{HD}(R_1, R_2): the share of response bits that differ.

Uniqueness averages the distance between every pair of kk chips answering the same challenges. Ideal: 50%, so every bit is a coin flip between chips.

U=2k(k−1)∑i=1k−1∑j=i+1kHD(Ri,Rj)U = \frac{2}{k(k-1)} \sum_{i=1}^{k-1}\sum_{j=i+1}^{k} \mathrm{HD}(R_i, R_j)

Reliability measures how much a chip disagrees with its own reference response RiR_i over TT repeated reads Ri,tR_{i,t}, at different temperatures and voltages. Ideal: 100%.

Reli=1−1T∑t=1THD(Ri,Ri,t)\text{Rel}_i = 1 - \frac{1}{T}\sum_{t=1}^{T} \mathrm{HD}(R_i, R_{i,t})

Uniformity is the share of ones in a response; ideal 50%, otherwise an attacker can guess. Bit-aliasing checks that a given bit position is not biased the same way on every chip.

The best picture of a PUF’s quality is the two Hamming-distance distributions side by side. Below is a simulation of 40 chips with 64-stage arbiter PUFs (the script is in this site’s repository, tools/puf-sim.mjs). Hover over the bars to see exact values.

Intra-chip vs inter-chip Hamming distanceRe-reading the same chip gives responses that differ in 2.6% of bits on average, while two different chips differ in 50.0%. The two distributions do not overlap.0%15%30%45%60%00.250.50.751Fraction of response bits that differ (Hamming distance)Share of comparisonsAccept below τ = 0.2Same chipDifferent chips
Show the numbers
MetricSimulatedIdeal
Uniqueness (mean inter-chip HD)50.0%50%
Reliability (1 − mean intra-chip HD)97.4%100%
Uniformity (share of 1-bits)49.7%50%
Worst intra-chip HD8.6%as low as possible
Closest inter-chip HD31.3%as high as possible
Simulated with 40 chips, 64-stage arbiter PUFs, 128-bit responses and 10 noisy reads each. Because the two humps never overlap, any threshold between them separates "same chip" from "impostor" without error.

The gap between the two humps is what makes authentication possible. A verifier picks a threshold τ\tau inside the gap: a distance below τ\tau means “same chip, a little noise”; above it means “a different chip”.

Using a PUF to log in

The simplest protocol has two phases. Enrolment happens once, in a trusted place such as the factory: the verifier applies many random challenges and stores the responses. Authentication happens in the field, every time the device connects.

Scroll sideways to see the whole diagram.

PUF enrolment and authenticationOnce, in a trusted place, many challenges are applied and the challenge-response pairs are stored. Later, the verifier sends an unused challenge, compares the chip's answer with the stored response, accepts if the Hamming distance is under a threshold, and otherwise rejects.ENROLMENT, ONCE, IN A TRUSTED PLACEAUTHENTICATION, EVERY LOGINSTORED RHD > τManufacture chipvariation is baked inApply challengesthousands of random CStore CRPs(C, R) in secure DBPick unused Cnever reuse a pairChip answers R′noisy re-readCompareHD(R, R′) ≤ τ ?Acceptretire this CRPReject
Why each pair is used only once. An eavesdropper who records a challenge and its response learns nothing useful for the next login, because that challenge is never asked again.

Two rules make this safe. First, the verifier never reuses a challenge, so a recorded CRP is useless to an eavesdropper. Second, the comparison uses a threshold instead of exact equality, because PUF responses are noisy.

In a large deployment, such as thousands of vehicles roaming between roadside units, one central verifier becomes a bottleneck and a single point of failure. In my research we anchor the enrolled data on a blockchain ledger instead, storing only hashes of expected responses, so any edge verifier can check a device without a central database (read the paper).

Scroll sideways to see the whole diagram.

PUF authentication with a blockchain ledgerAn IoT device asks an edge verifier to authenticate it; the verifier fetches a stored challenge and response hash from the ledger, challenges the device, checks the PUF response, logs the event and issues a session key.AUTH REQUESTFETCH CRPC, H(R)CHALLENGE CRESPONSE RLOG EVENTSESSION KEYR = PUF(C)CHECK H(R)IoT devicePUF on chipEdge verifiergateway or RSUBlockchain ledgerCRP commitmentscallreplyone-way eventsuccessful outcome
How a device proves who it is. The ledger stores only a hash of each expected response, so a stolen ledger copy does not reveal the PUF. The device never stores a key: it regenerates its answer from the silicon each time.

Turning a noisy response into a key

Authentication tolerates a few flipped bits, but cryptography does not: a key that differs by one bit is a different key. Weak PUFs therefore use a fuzzy extractor, built from an error-correcting code.

Scroll sideways to see the whole diagram.

Fuzzy extractor: from a noisy response to a stable keyAt enrolment, Gen turns the response R into a key K and public helper data W. Later, Rep combines a noisy response R′ with W to recover the same key K.ENROLMENT (Gen)EVERY BOOT (Rep)HELPER DATA WResponse Rfrom the PUFGenencode with ECCKey Kused, never storedNoisy response R′a few bits flippedRepdecode, correct errorsSame key Kbit-exact
Helper data can be public. W tells the decoder how to fix errors but, by design, leaks too little about R to recover K without the physical chip.

At enrolment, the Gen procedure picks a random codeword, XORs it with the response and publishes the result as helper data WW. Later, Rep XORs the noisy response R′R' with WW, which gives the codeword plus the few bit errors, decodes it to remove those errors, and recovers the exact key. Practical designs add a few tricks before the code:

  • Majority voting: read the PUF several times and keep the most common value of each bit.
  • Dark-bit masking: at enrolment, find the unstable bits and simply never use them.
  • Concatenated codes: a repetition code inside a BCH or Reed–Muller code handles high error rates with less helper data.

How PUFs get attacked

Modelling attacks are the biggest threat to strong PUFs. Remember the additive delay model: the response is the sign of a linear function of ϕ(c)\boldsymbol{\phi}(c). That means an attacker who eavesdrops on enough CRPs can train a linear classifier, such as logistic regression, and predict the PUF’s answer to any new challenge. The chip is then cloned in software.

The chart below shows that attack in simulation. A plain 64-stage arbiter PUF falls after a few hundred CRPs. XOR-ing four independent chains makes the function non-linear in ϕ\boldsymbol{\phi}, and the same attack stays at the level of a coin flip.

Machine-learning attack accuracy vs collected CRPsLogistic regression predicts an arbiter PUF with 99.4% accuracy after 10000 challenge-response pairs, but stays near 50% on a 4-XOR arbiter PUF.40%50%60%70%80%90%100%501002005001k2k5k10kChallenge–response pairs the attacker collected (log scale)Prediction accuracy on unseen challengescoin flipArbiter4-XOR
Show the numbers
CRPs collectedArbiter PUF4-XOR arbiter PUF
5069.7%49.7%
10077.4%50.3%
20087.5%50.2%
50093.3%51.7%
1,00096.3%47.9%
2,00098.5%49.7%
5,00098.8%49.1%
10,00099.4%48.7%
Logistic regression on the parity features Φ(c), tested on 3,000 fresh challenges. A few hundred eavesdropped pairs are enough to clone a plain arbiter PUF in software. XOR-ing four chains defeats this linear attack, although stronger attacks (more CRPs, neural networks, side channels) can still succeed.

XOR is not the end of the story: with enough CRPs, specialised logistic-regression variants and neural networks do break XOR arbiter PUFs with more chains, and noise and power side channels leak information too. Defences therefore combine several layers:

  • Never expose raw CRPs. Hash or encrypt responses inside the device, and limit how many challenges can be asked.
  • Use non-linear designs such as XOR, feed-forward or interpose PUFs, sized against current attacks.
  • Bind the PUF to a protocol that uses each CRP once and refreshes enrolment data securely.
  • Measure, don’t assume. Evaluate uniqueness, reliability and attack resistance on real hardware across temperature and voltage. We built PUFAnalytics, a Python library, for exactly this kind of evaluation.

Try it yourself

This self-contained script builds two simulated arbiter PUFs, measures their Hamming distances and then clones one with logistic regression. It needs only NumPy.

puf_demo.pypip install numpy, then python puf_demo.py
import numpy as np

rng = np.random.default_rng(seed=1)
N_STAGES = 64

def features(challenges):
    """Map 0/1 challenges (rows) to the parity feature vector Φ of the additive delay model."""
    signs = 1 - 2 * challenges                        # 0 -> +1, 1 -> -1
    phi = np.cumprod(signs[:, ::-1], axis=1)[:, ::-1]  # Φ_i = Π_{j>=i} (1 - 2c_j)
    return np.hstack([phi, np.ones((len(challenges), 1))])  # + bias term

class ArbiterPUF:
    def __init__(self, n=N_STAGES, noise=0.05, rng=rng):
        self.w = rng.normal(size=n + 1)   # stage delay differences, fixed at manufacture
        self.noise, self.rng = noise, rng

    def respond(self, challenges, noisy=True):
        delta = features(challenges) @ self.w
        if noisy:
            delta += self.rng.normal(scale=self.noise * np.linalg.norm(self.w), size=len(delta))
        return (delta > 0).astype(int)

def hamming(a, b):
    return np.mean(a != b)

chip_a, chip_b = ArbiterPUF(), ArbiterPUF()
C = rng.integers(0, 2, size=(128, N_STAGES))

print(f"same chip, two reads : {hamming(chip_a.respond(C), chip_a.respond(C)):.3f}")
print(f"chip A vs chip B     : {hamming(chip_a.respond(C), chip_b.respond(C)):.3f}")

# --- Modelling attack: learn w from eavesdropped CRPs with logistic regression ---
def train_logreg(X, y, epochs=300, lr=0.5):
    w = np.zeros(X.shape[1])
    for _ in range(epochs):
        p = 1 / (1 + np.exp(-X @ w))
        w -= lr * X.T @ (p - y) / len(y)
    return w

C_train = rng.integers(0, 2, size=(2000, N_STAGES))
C_test = rng.integers(0, 2, size=(5000, N_STAGES))
w_hat = train_logreg(features(C_train), chip_a.respond(C_train, noisy=False))
pred = (features(C_test) @ w_hat > 0).astype(int)
print(f"clone accuracy       : {np.mean(pred == chip_a.respond(C_test, noisy=False)):.3f}")

A run on my machine prints:

same chip, two reads : 0.031
chip A vs chip B     : 0.531
clone accuracy       : 0.974

Try changing noise, or replace ArbiterPUF with an XOR of four instances and watch the clone accuracy fall to about 50%.

Summary

  • A PUF derives a secret from manufacturing variation, so there is no stored key to steal.
  • Strong PUFs answer many challenges and suit authentication; weak PUFs derive one key.
  • Quality is judged by uniqueness (about 50%), reliability (close to 100%) and uniformity (about 50%).
  • Noise is handled by thresholds for authentication and fuzzy extractors for keys.
  • Linear designs such as the plain arbiter PUF can be cloned with machine learning, so real systems need non-linear designs and protocols that never reveal raw CRPs.

Further reading

  • B. Gassend, D. Clarke, M. van Dijk and S. Devadas, “Silicon physical random functions,” ACM CCS, 2002.
  • G. E. Suh and S. Devadas, “Physical unclonable functions for device authentication and secret key generation,” DAC, 2007.
  • J. Guajardo, S. Kumar, G.-J. Schrijen and P. Tuyls, “FPGA intrinsic PUFs and their use for IP protection,” CHES, 2007.
  • Y. Dodis, L. Reyzin and A. Smith, “Fuzzy extractors: how to generate strong keys from biometrics and other noisy data,” EUROCRYPT, 2004.
  • U. Rührmair, F. Sehnke, J. Sölter, G. Dror, S. Devadas and J. Schmidhuber, “Modeling attacks on physical unclonable functions,” ACM CCS, 2010.