Skip to content

[tvla] Fix plotting issues with new database and metadata format #270

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analysis/configs/tvla_cfg_aes_specific_byte0_rnd0.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_file: projects/simple_capture_aes_sca
project_file: ../capture/projects/simple_capture_aes_sca
trace_file: null
trace_start: null
trace_end: null
Expand Down
5 changes: 4 additions & 1 deletion analysis/configs/tvla_cfg_kmac.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_file: projects/opentitan_simple_kmac.cwp
project_file: ../capture/projects/simple_capture_kmac_sca
trace_file: null
trace_start: null
trace_end: null
Expand All @@ -14,3 +14,6 @@ ttest_step_file: null
plot_figures: true
general_test: true
mode: kmac
filter_traces: true
trace_threshold: 1000
trace_db: ot_trace_library
7 changes: 5 additions & 2 deletions analysis/configs/tvla_cfg_otbn_keygen.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_file: projects/opentitan_otbn_vertical_keygen.cwp
project_file: ../capture/projects/otbn_vertical_sca_cw310_keygen
trace_file: null
trace_start: null
trace_end: null
Expand All @@ -16,4 +16,7 @@ general_test: true
mode: otbn
key_len_bytes: 40
sample_start: null
num_samples : 3500
num_samples : null
filter_traces: true
trace_threshold: 1000
trace_db: ot_trace_library
7 changes: 5 additions & 2 deletions analysis/configs/tvla_cfg_otbn_modinv.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_file: projects/opentitan_otbn_vertical_modinv.cwp
project_file: ../capture/projects/otbn_vertical_sca_cw310_modinv
trace_file: null
trace_start: null
trace_end: null
Expand All @@ -16,4 +16,7 @@ general_test: true
mode: otbn
key_len_bytes: 32
sample_start: null
num_samples : 10000
num_samples : null
filter_traces: true
trace_threshold: 1000
trace_db: ot_trace_library
5 changes: 4 additions & 1 deletion analysis/configs/tvla_cfg_sha3.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_file: projects/opentitan_simple_sha3.cwp
project_file: ../capture/projects/simple_capture_sha3_sca
trace_file: null
trace_start: null
trace_end: null
Expand All @@ -14,3 +14,6 @@ ttest_step_file: null
plot_figures: true
general_test: true
mode: sha3
filter_traces: true
trace_threshold: 1000
trace_db: ot_trace_library
249 changes: 136 additions & 113 deletions analysis/tvla.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import inspect
import logging as log
import math
import multiprocessing
import os
import sys
Expand Down Expand Up @@ -162,6 +163,63 @@ def compute_histograms_aes(trace_resolution, rnd_list, byte_list, traces, leakag
return histograms


def tvla_plotting_fnc(axs, num_orders, ttest_trace, single_trace, threshold,
num_samples, sample_start, metadata):
"""Plotting trace in different colors, depending on where the trigger is high
"""
c = np.ones(num_samples)
xaxs = range(sample_start, sample_start + num_samples)
offset = int(metadata["offset_samples"])
# Catch case where trigger data isn't saved to project file (e.g. older measurement)
try:
trigger_samples = int(metadata["samples_trigger_high"])
except KeyError:
trigger_samples = num_samples + offset
trigger_low = trigger_samples - (sample_start + offset)
trigger_high = 0
if offset < 0:
trigger_high = abs(offset)
if trigger_low < 0:
trigger_low = 0
if trigger_low > num_samples:
trigger_low = num_samples
axs[0].set_ylabel("trace")
if trigger_high > 0:
axs[0].plot(xaxs[:trigger_high],
single_trace[:trigger_high],
"grey",
label='trigger low')
if trigger_low > trigger_high:
axs[0].plot(xaxs[trigger_high:trigger_low],
single_trace[trigger_high:trigger_low],
"k",
label='trigger high')
if trigger_low < num_samples:
axs[0].plot(xaxs[trigger_low:],
single_trace[trigger_low:],
"grey",
label='trigger low')
axs[0].legend(loc='upper right', prop={'size': 7})
for i_order in range(num_orders):
axs[1 + i_order].set_ylabel('t-test ' + str(i_order + 1))
axs[1 + i_order].plot(xaxs, c * threshold, "r")
axs[1 + i_order].plot(xaxs, -threshold * c, "r")
if trigger_high > 0:
axs[1 + i_order].plot(xaxs[:trigger_high],
ttest_trace[i_order, 0,
0][:trigger_high], "grey")
if trigger_low > trigger_high:
axs[1 + i_order].plot(
xaxs[trigger_high:trigger_low],
ttest_trace[i_order, 0, 0][trigger_high:trigger_low], "k")
if trigger_low < num_samples:
axs[1 + i_order].plot(xaxs[trigger_low:],
ttest_trace[i_order, 0,
0][trigger_low:], "grey")

return axs


@app.command()
def run_tvla(ctx: typer.Context):
"""Run TVLA described in "Fast Leakage Assessment"."""
Expand Down Expand Up @@ -467,7 +525,10 @@ def run_tvla(ctx: typer.Context):
# Eventually, we can drop this.
if i_step == 0:
if OTTraceLib:
keys_nparrays = project.get_keys()
if cfg["mode"] == "sha3":
keys_nparrays = project.get_plaintexts()
else:
keys_nparrays = project.get_keys()
else:
# Convert all keys from the project file to numpy
# arrays once.
Expand Down Expand Up @@ -698,72 +759,81 @@ def run_tvla(ctx: typer.Context):

# Metadata text variable for plot
textbox = ""
# Metadata currently not implemented for OTTraceLib
if not OTTraceLib:
# Catch case where certain metadata isn't saved to project file (e.g. older measurement)
try:
pll_freq = float(metadata['ChipWhisperer']
['General Settings']['pll_frequency']) / 1e6
textbox = textbox + "PLL:\n" + str(pll_freq) + " MHz\n\n"
except KeyError:
textbox = textbox
try:
pll_freq = float(metadata['ChipWhisperer']
['General Settings']['sample_rate']) / 1e6
textbox = textbox + "ADC:\n" + str(pll_freq) + " MS/s\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Masks off:\n" + metadata[
'ChipWhisperer']['General Settings']['masks_off'] + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Samples:\n" + metadata['ChipWhisperer'][
'General Settings']['num_samples'] + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Offset:\n" + metadata['ChipWhisperer'][
'General Settings']['offset'] + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Scope gain:\n" + metadata[
'ChipWhisperer']['General Settings']['scope_gain'] + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Traces:\n" + metadata['ChipWhisperer'][
'General Settings']['num_traces'] + "\n\n"
except KeyError:
textbox = textbox
if textbox != "":
# remove last two linebreaks
textbox = textbox[:-2]
# Catch case where certain metadata isn't saved to project file (e.g. older measurement)
try:
sampling_rate = float(metadata['sampling_rate']) / 1e6
textbox = textbox + "Sample rate:\n" + str(
math.floor(sampling_rate)) + " MS/s\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Masks off:\n" + metadata['masks_off'] + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Samples:\n" + str(
metadata['num_samples']) + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Offset:\n" + str(
metadata['offset_samples']) + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Scope gain:\n" + str(
metadata['scope_gain']) + "\n\n"
except KeyError:
textbox = textbox
try:
textbox = textbox + "Traces:\n" + str(num_traces) + "\n\n"
except KeyError:
textbox = textbox
if textbox != "":
# remove last two linebreaks
textbox = textbox[:-2]

# Plotting figures for t-test statistics vs. time.
log.info("Plotting T-test Statistics vs. Time.")
xaxs = range(sample_start, sample_start + num_samples)
fig, axs = plt.subplots(num_orders + 1, 1, sharex=True)
if cfg["mode"] == "aes" and general_test is False:
# By default the figures are saved under tmp/t_test_round_x_byte_y.png.
for i_rnd in range(num_rnds):
for i_byte in range(num_bytes):

c = np.ones(num_samples)
fig, axs = plt.subplots(num_orders + 1,
1,
sharex=True)

axs[0].plot(xaxs, single_trace, "k")
axs[0].set_ylabel("trace")
for i_order in range(num_orders):
axs[i_order + 1].plot(
ttest_trace[i_order, rnd_ext[i_rnd],
byte_ext[i_byte]], 'k')
axs[i_order + 1].plot(c * threshold, 'r')
axs[i_order + 1].plot(-threshold * c, 'r')
axs[i_order + 1].set_ylabel('t-test ' + str(i_order + 1))
axs = tvla_plotting_fnc(axs, num_orders, ttest_trace,
single_trace, threshold,
num_samples, sample_start,
metadata)

# Catch case where datetime data isn't saved
# to project file (e.g. older measurement)
try:
axs[0].set_title("TVLA of " + "aes_t_test_round_" +
str(rnd_list[i_rnd]) + "_byte_" +
str(byte_list[i_byte]) + "\n" +
"Captured: " + metadata['datetime'])
except KeyError:
axs[0].set_title("TVLA of " + "aes_t_test_round_" +
str(rnd_list[i_rnd])
) + "_byte_" + str(byte_list[i_byte])

# Add metadata to plot
if textbox != "":
left, width = .67, .5
bottom, height = .25, .5
right = left + width
top = bottom + height
plt.gcf().text(0.5 * (left + right),
0.5 * (bottom + top),
textbox,
fontsize=9,
horizontalalignment='center',
verticalalignment='center',
bbox=dict(boxstyle='round',
facecolor='w',
linewidth=0.6))
plt.subplots_adjust(right=0.84)
plt.xlabel("time [samples]")

filename = "aes_t_test_round_" + str(rnd_list[i_rnd])
Expand All @@ -775,66 +845,18 @@ def run_tvla(ctx: typer.Context):
plt.close()

else:
c = np.ones(num_samples)
fig, axs = plt.subplots(3, sharex=True)
axs = tvla_plotting_fnc(axs, num_orders, ttest_trace, single_trace,
threshold, num_samples, sample_start,
metadata)

# Catch case where datetime data isn't saved to project file (e.g. older measurement)
try:
axs[0].set_title("TVLA of " +
(cfg["project_file"]).rsplit('/')[1] + "\n" +
"Captured: " + project.config['ChipWhisperer']
['General Settings']['datetime'])
(cfg["project_file"]).rsplit('/')[3] + "\n" +
"Captured: " + metadata["datetime"])
except KeyError:
axs[0].set_title("TVLA of " +
(cfg["project_file"]).rsplit('/')[1])

# Catch case where trigger data isn't saved to project file (e.g. older measurement)
try:
# Plot trace in different colors, depending on where the trigger is high
trigger_samples = int(
project.config['ChipWhisperer']['General Settings']
['samples_trigger_high'])
offset = int(project.config['ChipWhisperer']
['General Settings']['offset'])
trigger_high = trigger_samples - (sample_start + offset)
if trigger_high < 0:
trigger_high = 0
axs[0].set_ylabel("trace")
if trigger_high >= num_samples:
axs[0].plot(xaxs, single_trace, "k")
else:
axs[0].plot(xaxs[:trigger_high],
single_trace[:trigger_high],
"k",
label='trigger high')
axs[0].plot(xaxs[trigger_high:],
single_trace[trigger_high:],
"grey",
label='trigger low')
axs[0].legend(loc='upper right', prop={'size': 7})
for i_order in range(num_orders):
axs[1 + i_order].set_ylabel('t-test ' + str(i_order + 1))
axs[1 + i_order].plot(xaxs, c * threshold, "r")
axs[1 + i_order].plot(xaxs, -threshold * c, "r")
if trigger_high >= num_samples:
axs[1 + i_order].plot(xaxs, ttest_trace[i_order, 0, 0],
"k")
else:
axs[1 + i_order].plot(
xaxs[:trigger_high],
ttest_trace[i_order, 0, 0][:trigger_high], "k")
axs[1 + i_order].plot(
xaxs[trigger_high:],
ttest_trace[i_order, 0, 0][trigger_high:], "grey")
except KeyError:
axs[0].plot(xaxs, single_trace, "k")
axs[0].set_ylabel("trace")
for i_order in range(num_orders):
axs[1 + i_order].plot(xaxs, ttest_trace[i_order, 0, 0],
"k")
axs[1 + i_order].plot(xaxs, c * threshold, "r")
axs[1 + i_order].plot(xaxs, -threshold * c, "r")
axs[1 + i_order].set_ylabel('t-test ' + str(i_order + 1))
(cfg["project_file"]).rsplit('/')[3])

# Add metadata to plot
if textbox != "":
Expand All @@ -852,6 +874,7 @@ def run_tvla(ctx: typer.Context):
facecolor='w',
linewidth=0.6))
plt.subplots_adjust(right=0.84)

plt.xlabel("time [samples]")
plt.savefig('tmp/figures/' + cfg["mode"] + '_fixed_vs_random.png')
plt.show()
Expand Down
2 changes: 2 additions & 0 deletions capture/capture_aes.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ def main(argv=None):
metadata["cfg"] = cfg
metadata["num_samples"] = scope.scope_cfg.num_samples
metadata["offset_samples"] = scope.scope_cfg.offset_samples
metadata["sampling_rate"] = scope.scope_cfg.sampling_rate
metadata["num_traces"] = capture_cfg.num_traces
metadata["scope_gain"] = scope.scope_cfg.scope_gain
metadata["cfg_file"] = str(args.cfg)
# Store bitstream information.
Expand Down
2 changes: 2 additions & 0 deletions capture/capture_kmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@ def main(argv=None):
metadata["cfg"] = cfg
metadata["num_samples"] = scope.scope_cfg.num_samples
metadata["offset_samples"] = scope.scope_cfg.offset_samples
metadata["sampling_rate"] = scope.scope_cfg.sampling_rate
metadata["num_traces"] = capture_cfg.num_traces
metadata["scope_gain"] = scope.scope_cfg.scope_gain
metadata["cfg_file"] = str(args.cfg)
# Store bitstream information.
Expand Down
7 changes: 7 additions & 0 deletions capture/capture_otbn.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,13 @@ def main(argv=None):
metadata["num_samples"] = scope.scope_cfg.num_samples
metadata["offset_samples"] = scope.scope_cfg.offset_samples
metadata["scope_gain"] = scope.scope_cfg.scope_gain
if cfg["capture"]["scope_select"] == "husky":
metadata[
"sampling_rate"] = scope.scope.scope.clock.adc_freq / scope.scope.scope.adc.decimate
metadata["samples_trigger_high"] = scope.scope.scope.adc.trig_count
else:
metadata["sampling_rate"] = scope.scope_cfg.sampling_rate
metadata["num_traces"] = capture_cfg.num_traces
metadata["cfg_file"] = str(args.cfg)
# Store bitstream information.
metadata["fpga_bitstream_path"] = cfg["target"]["fpga_bitstream"]
Expand Down
Loading