# Python [Learning] - pypuf > [name=D] ## Arbiter PUFs and Compositions - Arbier PUF - XOR Arbiter PUF - Feed-Forward (XOR) Arbiter PUF - Lightweight Secure PUF - Permutation PUF - Interpose PUF ### Arbiter PUF - `n` : challenge length - `seed` : 用來讓結果可重現的,假如是同一個 seed 的話,就會產生一模一樣的 PUF - `eval()` : to evaluate challenges, provide a list of challenges - `noisiness` : the noisee level, `0.0` ~ `1.0` - `N` : N 組挑戰 ```python= from pypuf.simulation import ArbiterPUF from pypuf.io import random_inputs puf = ArbiterPUF(n=64, seed=1, noisiness=.2) puf.eval(random_inputs(n=64, N=3, seed=2)) ``` ### XOR Arbiter PUF - `k` : the amount of Arbiter PUFs ```python= from pypuf.simulation import XORArbiterPUF from pypuf.io import random_inputs puf = XORArbiterPUF(n=64, k=8, seed=1, noisiness=.05) puf.eval(random_inputs(n=64, N=3, seed=2)) # array([-1, 1, -1], dtype=int8) ``` ### Feed-Forward (XOR) Arbiter PUF - `ff` : list of forward connections ```python= from pypuf.simulation import XORFeedForwardArbiterPUF from pypuf.io import random_inputs puf = XORFeedForwardArbiterPUF(n=128, k=4, ff=[(32, 68)], seed=1) puf.eval(random_inputs(n=128, N=6, seed=2)) ``` ### Lightweight Secure PUF 每條 XOR Arbiter PUF 鏈不再使用相同的 challenge,而是對一個主 challenge 做轉換,產生出不同的子 challenge 後,再放進 Arbiter PUFs 且互相 XOR 輸出的 response ```python= from pypuf.simulation import LightweightSecurePUF from pypuf.io import random_inputs puf = LightweightSecurePUF(n=64, k=8, seed=1, noisiness=.05) puf.eval(random_inputs(n=64, N=3, seed=2)) ``` ### Permutation PUF 和 Lightweight Secure PUF 的實作類似,差別是不是用自己所定義的 transformation 函數作為子挑戰的產生,而是變成用排列(Permutation)的方式產生,這樣可以避免攻擊者逆推出 transformation,其中 1. 任兩組排列中,不能有相同的位元從相同位置移動到相同位置(也就是不能出現「兩組排列都把第 i 位移到第 j 位」這種情況) 2. 每一組排列都不能有固定點(fix point),也就是沒有任何一個位元保留在原本的位置 ```python= from pypuf.simulation import PermutationPUF from pypuf.io import random_inputs puf = PermutationPUF(n=64, k=8, seed=1, noisiness=.05) puf.eval(random_inputs(n=64, N=3, seed=2)) ``` ### Interpose PUF 會分為上下兩層(upper, lower layer),會先將 challenge 輸入到 upper layer 進行運算,然後將該回應插入(Interpose) 到 challenge 的中間位置,形成新的 challenge,再將新 challenge 輸入到 lower layer,最後經過運算後得到最終的 response ```python= from pypuf.simulation import InterposePUF from pypuf.io import random_inputs puf = InterposePUF(n=64, k_up=8, k_down=8, seed=1, noisiness=.05) puf.eval(random_inputs(n=64, N=3, seed=2)) ``` ## Additive Delay Model - LTFArray - NoisyLTFArray (Gaussian noise) ### LTFArray - weight_array : ndarray of floats with shape `(k,n)`,此陣列中每個 LTF 的權重 - transform : 輸入轉換方法 - combiner : 用來合併每個 LTF 輸出的組合函數,預設為 XOR - bias : ndarray of floats with shape `(k, )`,每個 LTF 的偏差值,預設為 0 Parameters: - 要進行評估的 challenges - `ndarray` of shape(N, `challenge_length`) - N 維陣列(要評估 challenge 的數目) - (1, `challenge_length`) 只評估一個 challenge - (10, `challenge_length`) 評估十個 challenge - (N, 0) 為空陣列,來指定希望得到多少筆回應 Returns : - `ndarry` of shape(N, `response_length`) ```python= from pypuf.simulation import LTFArray from numpy import array, ones my_puf = LTFArray(ones(shape=(1, 4)), transform='id') my_puf.eval(array([[1, 1, -1, 1]])) # array([1]) my_puf.eval(array([[1, -1, -1, -1]])) # array([-1]) ``` ## Base Class for Simulations - `r` : 同一組 challenge 模擬 r 次,所以會有 r 個 responses ```python= from pypuf.simulation import XORArbiterPUF from pypuf.io import random_inputs puf = XORArbiterPUF(n=64, k=4, noisiness=.02, seed=1) responses = puf.r_eval(3, random_inputs(N=6, n=64, seed=4)) responses[0, :, :] # 第一組 challenge 模擬 3 次後,分別得到的 3 個 responses # array([[-1., 1., 1.]]) responses[1, :, :] . . . responses[5, :, :] # 總共有 6 組 challenge ``` ## Data ### Generating Uniform Random Challenges `pypuf` 使用 `{-1,1}` 來表示 challenges 和 responses,如果要將其轉換至傳統的 `{0,1}` 的話,可以使用 `x = (1 - x) // 2` 做 encode,用 `x = 1 - 2 * x` 做 decode ```python= import numpy as np import pypuf.io challenges = pypuf.io.ramdom_inputs(n=64, N=10, seed=1) np.unique(challenges) # array([-1, 1], dtype=int8) challenges01 = (1 - challenges) // 2 np.unique(challenges01) # array([0, 1], dtype=int8) challenges11 = 1 - 2 * challenges01 np.unique(challenges11) (challenges11 == challenges).all() # True ``` ### Storing Challenge-Response Data `pypuf` 會儲存 challenge-response 資料,他們分別為 2 個 numpy arrays ```python= import numpy as np import pypuf.io challenges = np.array([[-1, -1, -1, -1], [-1, -1, -1, 1]]) responses = np.array([1, 1]) crp = pypuf.io.ChallengeResponseSet(challenges, responses) ``` 生成 challenges 和 responses ```python= import pypuf.simulation import pypuf.io puf = pypuf.simulation.ArbiterPUF(n=64, seed=1) crp = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=2) crp.challenges # array([ [64 個 1 或 -1], [64 個 1 或 -1], [64 個 1 或 -1] ]) crp.responses # array([[[-1.]], [[ 1.]], [[-1.]]]) ``` 將 `pypuf` CRP data 可以儲存成 `.npz` ```python+= crp.save('crps.npz') crp_loaded = pypuf.io.ChallengeResponseSet.load('crps.npz') crp == crp_loaded # True ``` 取 challenges-responses pair ```python+= # 取 第一個 pair crp[0] # (array([-1,...), array([[1.]])) crp[:10] # <10 CRPs with challenge length 64 and response length 1, each response measured 1 time(s)> ``` ## Distance / Similarity ```python= from pypuf.simulation import XORArbiterPUF from pypuf.io import ChallengeResponseSet from pypuf.metrics import accuracy puf = XORArbiterPUF(n=128, k=4, noisiness=.1, seed=1) test_set = ChallengeResponseSet.from_simulation(puf, N=1000, seed=2) accuracy(puf, test_set) # array([0.823]) puf = XORArbiterPUF(n=64, k=4, noisiness=.3, seed=2) test_set = ChallengeResponseSet.from_simulation(puf, N=1000, seed=2, r=5) accuracy(puf, test_set) # array([0.706]) ```