This commit is contained in:
xenia 2021-04-25 23:04:48 -04:00
parent 9876dcff1f
commit bc068c75a4
3 changed files with 71 additions and 49 deletions

View File

@ -66,49 +66,50 @@ def align(db, ntraces):
alignments[i] = lag
alignments -= numpy.min(alignments)
max_start = max(alignments)
min_end = 700
traces = numpy.zeros((ntraces, 800), 'double')
for i in range(ntraces):
traces[i, alignments[i]:alignments[i]+700] = db["traces"][i]
return traces
return traces[:, max_start:min_end]
def main(db):
ntraces = 1000
traces = align(db, ntraces)
# P - (n,m) array of n predictions for each of the m candidates
# O - (n,t) array of n traces with t samples each
# returns an (m,t) correlation matrix of m traces t samples each
class Correlator:
def __init__(self, P):
self.P = P - numpy.mean(P, axis=0)
self.tmp1 = numpy.einsum("nm,nm->m", self.P, self.P, optimize='optimal')
self.P = self.P.transpose()
# for i in range(10):
# plt.plot(traces[i], color=numpy.hstack((numpy.random.random(3), [0.5])))
# plt.show()
def corr_submatrix(self, O):
O -= numpy.mean(O, axis=0)
numerator = self.P @ O
tmp2 = numpy.einsum("nt,nt->t", O, O, optimize='optimal')
denominator = numpy.sqrt(numpy.outer(self.tmp1, tmp2))
return numerator / denominator
logger.info("making model")
def attack_firstorder(db, traces, ntraces):
logger.info("making first order model")
model = numpy.repeat(numpy.arange(256, dtype='uint8'), ntraces).reshape((256, ntraces))
for i in tqdm.trange(ntraces):
(pt, ct, key, mask, desync) = db["metadata"][i]
pt_v = pt[2]
mask_v = mask[15]
model[:, i] = AES_SBOX[model[:, i] ^ pt_v] ^ mask_v
model = numpy_popcount.popcount(model).astype("double")
# O - (n,t) array of n traces with t samples each
# P - (n,m) array of n predictions for each of the m candidates
# returns an (m,t) correaltion matrix of m traces t samples each
def corr_submatrix(O, P):
O -= numpy.mean(O, axis=0)
P -= numpy.mean(P, axis=0)
numerator = numpy.einsum("nm,nt->mt", P, O, optimize='optimal')
denominator = numpy.sqrt(numpy.outer((P * P).sum(axis=0), (O * O).sum(axis=0)))
return numerator / denominator
model = numpy_popcount.popcount(model).astype("double").transpose()
# boring, slow, uses too much RAM
# input_matrix = numpy.vstack((model, traces.transpose()))
# coefs = numpy.corrcoef(input_matrix)[0:256, 256:]
# uwu
coefs = corr_submatrix(traces, model.transpose())
correlator = Correlator(model)
coefs = correlator.corr_submatrix(traces)
# plot absmax
coefs = numpy.abs(coefs)
@ -116,35 +117,56 @@ def main(db):
plt.plot(max_by_key)
plt.show()
# logger.info("making 2nd order")
# traces = traces.transpose()
# traces_x = numpy.zeros((700*699//2, ntraces), 'double')
# tx_i = 0
# for i in tqdm.trange(700):
# for j in range(i+1, 700):
# traces_x[tx_i, :] = numpy.abs(traces[i, :] - traces[j, :])
# tx_i += 1
#
# logger.info("doing corr")
# ncolumns = 100
# step = traces_x.shape[0] // ncolumns
# all_coefs = None
# for i in tqdm.trange(ncolumns):
# start = i * step
# end = (i + 1) * step
# input_matrix = numpy.vstack((model, traces_x[start:end, :]))
# coefs = numpy.corrcoef(input_matrix)[0:256, 256:]
# if all_coefs is None:
# all_coefs = coefs
# else:
# all_coefs = numpy.hstack((all_coefs, coefs))
#
#
# all_coefs = numpy.abs(all_coefs)
# max_by_key = numpy.max(all_coefs, axis=1)
# plt.plot(max_by_key)
def attack_secondorder(db, traces, ntraces):
logger.info("making second order model")
model = numpy.repeat(numpy.arange(256, dtype='uint8'), ntraces).reshape((256, ntraces))
for i in tqdm.trange(ntraces):
(pt, ct, key, mask, desync) = db["metadata"][i]
pt_v = pt[2]
mask_v = mask[15]
model[:, i] = AES_SBOX[model[:, i] ^ pt_v]
model = numpy_popcount.popcount(model).astype("double").transpose()
logger.info("making second order combinations")
nticks = traces.shape[1]
traces_x = numpy.zeros((ntraces, nticks*(nticks - 1)//2), 'double')
tx_i = 0
for i in tqdm.trange(nticks):
for j in range(i+1, nticks):
traces_x[:, tx_i] = numpy.abs(traces[:, i] - traces[:, j])
tx_i += 1
logger.info("doing corr")
correlator = Correlator(model)
ncolumns = 10
step = traces_x.shape[1] // ncolumns
all_coefs = []
for i in tqdm.trange(ncolumns):
start = i * step
end = (i + 1) * step
coefs = correlator.corr_submatrix(traces_x[:, start:end])
all_coefs.append(coefs)
all_coefs = numpy.hstack(all_coefs)
all_coefs = numpy.abs(all_coefs)
max_by_key = numpy.max(all_coefs, axis=1)
plt.plot(max_by_key)
plt.show()
def main(db):
ntraces = 2000
traces = align(db, ntraces)
# for i in range(10):
# plt.plot(traces[i], color=numpy.hstack((numpy.random.random(3), [0.5])))
# plt.show()
attack_firstorder(db, traces, ntraces)
attack_secondorder(db, traces, ntraces)
if __name__ == "__main__":
from tqdm.contrib.logging import logging_redirect_tqdm

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 23 KiB

BIN
sca/ascad/second_order.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB