Skip to content

Commit

Permalink
Batch mode for Ibex SCA & new FI test
Browse files Browse the repository at this point in the history
This commit adds the command handler for:
- ibex_sca_tl_write_batch_fvsr
- ibex_sca_tl_write_batch_fvsr_fix_address
- ibex_sca_tl_write_batch_random
- ibex_sca_tl_write_batch_random_fix_address
- ibex_sca_tl_write_fvsr
- ibex_sca_tl_write_random
- ibex_sca_tl_read_batch_fvsr
- ibex_sca_tl_read_batch_fvsr_fix_address
- ibex_sca_tl_read_batch_random
- ibex_sca_tl_read_batch_random_fix_address
- ibex_sca_tl_read_fvsr
- ibex_sca_tl_read_random
- ibex_sca_register_file_write_batch_fvsr
- ibex_sca_register_file_write_batch_random
- ibex_sca_register_file_write_fvsr
- ibex_sca_register_file_write_random
- ibex_sca_register_file_read_batch_fvsr
- ibex_sca_register_file_read_batch_random
- ibex_sca_register_file_read_fvsr
- ibex_sca_register_file_read_random
- ibex_fi_char_sram_write

The device code is located in lowRISC/opentitan#22272 and the
binary was compiled from lowRISC/opentitan@7f7dbbc

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa committed Apr 11, 2024
1 parent c4575d2 commit 756001c
Show file tree
Hide file tree
Showing 6 changed files with 431 additions and 98 deletions.
151 changes: 106 additions & 45 deletions capture/capture_ibex.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import util.helpers as helpers
from target.communication.sca_ibex_commands import OTIbex
from target.communication.sca_prng_commands import OTPRNG
from target.communication.sca_trigger_commands import OTTRIGGER
from target.targets import Target, TargetConfig
from util import check_version, plot
Expand Down Expand Up @@ -54,11 +55,12 @@ def abort_handler_during_loop(this_project, sig, frame):
class CaptureConfig:
""" Configuration class for the current capture.
"""
capture_mode: str
test_mode: str
num_traces: int
num_segments: int
protocol: str
port: Optional[str] = "None"
batch_prng_seed: Optional[str] = "None"


def setup(cfg: dict, project: Path):
Expand Down Expand Up @@ -104,10 +106,15 @@ def setup(cfg: dict, project: Path):

logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501

# Determine if we are in batch mode or not.
batch = False
if "batch" in cfg["test"]["which_test"]:
batch = True

# Create scope config & setup scope.
scope_cfg = ScopeConfig(
scope_type = scope_type,
batch_mode = True,
batch_mode = batch,
bit = cfg[scope_type].get("bit"),
acqu_channel = cfg[scope_type].get("channel"),
ip = cfg[scope_type].get("waverunner_ip"),
Expand Down Expand Up @@ -143,38 +150,51 @@ def establish_communication(target, capture_cfg: CaptureConfig):
Returns:
ot_ibex: The communication interface to the Ibex SCA application.
ot_prng: The communication interface to the PRNG SCA application.
ot_trig: The communication interface to the SCA trigger.
"""
# Create communication interface to OT Ibex.
ot_ibex = OTIbex(target=target, protocol=capture_cfg.protocol)

# Create communication interface to OT PRNG.
ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol)

# Create communication interface to SCA trigger.
ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol)

return ot_ibex, ot_trig
return ot_ibex, ot_prng, ot_trig


def generate_data():
def generate_data(test_mode, num_data):
""" Returns data used by the test.
Either a fixed dataset or a random one is generated.
Returns:
data: Data used by the test.
data: The data set used for the test.
data_fixed: The fixed data set.
"""
fixed_data = random.randint(0, 1)
if fixed_data:
data = [0xDEADBEEF, 0xCDCDCDCD, 0xABADCAFE, 0x8BADF00D, 0xFDFDFDFD,
0xA5A5A5A5, 0xABABABAB, 0xC00010FF]
else:
data = []
for i in range(0, 8):
data.append(random.randint(0, 65535))
return data


def capture(scope: Scope, ot_ibex: OTIbex, capture_cfg: CaptureConfig,
project: SCAProject, target: Target):
data = []
data_fixed = 0xABBABABE
# First sample is always fixed.
sample_fixed = True
for i in range(num_data):
if "fvsr" in test_mode:
if sample_fixed:
data.append(data_fixed)
else:
data.append(random.getrandbits(32))
sample_fixed = random.getrandbits(32) & 0x1
elif "random" in test_mode:
tmp = random.getrandbits(32)
data.append(tmp)
else:
raise RuntimeError("Error: Invalid test mode!")
return data, data_fixed


def capture(scope: Scope, ot_ibex: OTIbex, ot_prng: OTPRNG,
capture_cfg: CaptureConfig, project: SCAProject, target: Target):
""" Capture power consumption during execution of Ibex SCA penetration tests.
Supports the following captures:
Expand All @@ -185,7 +205,8 @@ def capture(scope: Scope, ot_ibex: OTIbex, capture_cfg: CaptureConfig,
Args:
scope: The scope class representing a scope (Husky or WaveRunner).
ot_ibex: The OpenTitan AES communication interface.
ot_ibex: The communication interface to the Ibex SCA application.
ot_prng: The communication interface to the PRNG SCA application.
capture_cfg: The configuration of the capture.
project: The SCA project.
target: The OpenTitan target.
Expand All @@ -194,6 +215,14 @@ def capture(scope: Scope, ot_ibex: OTIbex, capture_cfg: CaptureConfig,
# Optimization for CW trace library.
num_segments_storage = 1

# Seed the PRNG used for generating random data.
if "batch" in capture_cfg.test_mode:
# Seed host's PRNG.
random.seed(capture_cfg.batch_prng_seed)

# Seed the target's PRNG.
ot_prng.seed_prng(capture_cfg.batch_prng_seed.to_bytes(4, "little"))

# Register ctrl-c handler to store traces on abort.
signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project))
# Main capture with progress bar.
Expand All @@ -202,34 +231,65 @@ def capture(scope: Scope, ot_ibex: OTIbex, capture_cfg: CaptureConfig,
while remaining_num_traces > 0:
# Arm the scope.
scope.arm()
data = generate_data()
if capture_cfg.capture_mode == "ibex.sca.register_file_read":
ot_ibex.register_file_read(capture_cfg.num_segments, data)
elif capture_cfg.capture_mode == "ibex.sca.register_file_write":
ot_ibex.register_file_write(capture_cfg.num_segments, data)
elif capture_cfg.capture_mode == "ibex.sca.tl_read":
ot_ibex.tl_read(capture_cfg.num_segments, data)
elif capture_cfg.capture_mode == "ibex.sca.tl_write":
ot_ibex.tl_write(capture_cfg.num_segments, data)
if "batch" in capture_cfg.test_mode:
num_data = capture_cfg.num_segments
else:
# In non-batch mode, 8 uint32 values are used.
num_data = 8
# Generate data set used for the test.
data, data_fixed = generate_data(capture_cfg.test_mode, num_data)
# Start the test based on the mode.
if "batch" in capture_cfg.test_mode:
if "fvsr" in capture_cfg.test_mode:
# In FvsR batch, the fixed dataset and the number of segments
# is transferred to the device. The rest of the dataset is
# generated on the device. Trigger is set number of segments.
ot_ibex.start_test(capture_cfg.test_mode, data_fixed, capture_cfg.num_segments)
elif "random" in capture_cfg.test_mode:
# In Random batch, number of segments is transferred to the
# device. number of segments random datasets are generated
# on the device. Trigger is set number of segments.
ot_ibex.start_test(capture_cfg.test_mode,
capture_cfg.num_segments)
else:
# In the non-batch mode, the dataset is generated in ot-sca and
# transferred to the device. Trigger is set once.
ot_ibex.start_test(capture_cfg.test_mode, data)

# Capture traces.
waves = scope.capture_and_transfer_waves(target)
assert waves.shape[0] == capture_cfg.num_segments

# Convert data into bytearray for storage in database.
data_bytes = []
for d in data:
data_bytes.append(d.to_bytes(4, "little"))
response = ot_ibex.ibex_sca_read_response()
# Check response. 0 for non-batch and the last data element in
# batch mode.
if "batch" in capture_cfg.test_mode:
assert response == data[-1]
else:
assert response == 0

# Store traces.
for i in range(capture_cfg.num_segments):
# Sanity check retrieved data (wave).
assert len(waves[i, :]) >= 1
# Store trace into database.
project.append_trace(wave = waves[i, :],
plaintext = b''.join(data_bytes),
ciphertext = None,
key = None)
if "batch" in capture_cfg.test_mode:
for i in range(capture_cfg.num_segments):
# Sanity check retrieved data (wave).
assert len(waves[i, :]) >= 1
# Store trace into database.
project.append_trace(wave = waves[i, :],
plaintext = data[i].to_bytes(4, 'little'),
ciphertext = None,
key = None)
else:
# Convert data into bytearray for storage in database.
data_bytes = []
for d in data:
data_bytes.append(d.to_bytes(4, "little"))
# Sanity check retrieved data (wave).
assert len(waves[0, :]) >= 1
# Store trace into database.
project.append_trace(wave = waves[0, :],
plaintext = b''.join(data_bytes),
ciphertext = None,
key = None)

# Memory allocation optimization for CW trace library.
num_segments_storage = project.optimize_capture(num_segments_storage)
Expand Down Expand Up @@ -279,21 +339,22 @@ def main(argv=None):
target, scope, project = setup(cfg, args.project)

# Create capture config object.
capture_cfg = CaptureConfig(capture_mode = cfg["test"]["which_test"],
capture_cfg = CaptureConfig(test_mode = cfg["test"]["which_test"],
num_traces = cfg["capture"]["num_traces"],
num_segments = scope.scope_cfg.num_segments,
protocol = cfg["target"]["protocol"],
port = cfg["target"].get("port"))
logger.info(f"Setting up capture {capture_cfg.capture_mode}...")
port = cfg["target"].get("port"),
batch_prng_seed = cfg["test"].get("batch_prng_seed"))
logger.info(f"Setting up capture {capture_cfg.test_mode}...")

# Open communication with target.
ot_ibex, ot_trig = establish_communication(target, capture_cfg)
ot_ibex, ot_prng, ot_trig = establish_communication(target, capture_cfg)

# Configure SW trigger.
ot_trig.select_trigger(1)

# Capture traces.
capture(scope, ot_ibex, capture_cfg, project, target)
capture(scope, ot_ibex, ot_prng, capture_cfg, project, target)

# Print plot.
print_plot(project, cfg, args.project)
Expand Down
38 changes: 29 additions & 9 deletions capture/configs/ibex_sca_chip.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,43 @@ target:
port: "/dev/ttyUSB1"
waverunner:
waverunner_ip: 192.168.33.128
num_segments: 20
num_segments: 1
# cycles will only be used if not given in samples
num_cycles: 100
offset_cycles: 0
# Do not capture 100 nops that are inserted to give the trigger time to rise.
offset_cycles: 100
# sampling rate needed for cycle to sample conversion
sampling_rate: 2500000000
channel: C1
sparsing: 0
capture:
scope_select: waverunner
num_traces: 5000
num_traces: 101
show_plot: True
plot_traces: 100
plot_traces: 20
trace_db: ot_trace_library
trace_threshold: 10000
trace_threshold: 50
test:
# which_test: ibex.sca.tl_write
# which_test: ibex.sca.tl_read
# which_test: ibex.sca.register_file_write
which_test: ibex.sca.register_file_read
# which_test: ibex_sca_tl_write_batch_fvsr
# which_test: ibex_sca_tl_write_batch_fvsr_fix_address
# which_test: ibex_sca_tl_write_batch_random
# which_test: ibex_sca_tl_write_batch_random_fix_address
# which_test: ibex_sca_tl_write_fvsr
# which_test: ibex_sca_tl_write_random
# which_test: ibex_sca_tl_read_batch_fvsr
# which_test: ibex_sca_tl_read_batch_fvsr_fix_address
# which_test: ibex_sca_tl_read_batch_random
# which_test: ibex_sca_tl_read_batch_random_fix_address
# which_test: ibex_sca_tl_read_fvsr
# which_test: ibex_sca_tl_read_random
# which_test: ibex_sca_register_file_write_batch_fvsr
# which_test: ibex_sca_register_file_write_batch_random
# which_test: ibex_sca_register_file_write_fvsr
# which_test: ibex_sca_register_file_write_random
# which_test: ibex_sca_register_file_read_batch_fvsr
# which_test: ibex_sca_register_file_read_batch_random
# which_test: ibex_sca_register_file_read_fvsr
which_test: ibex_sca_register_file_read_random
# seed for PRNG to generate sequence of plaintexts and keys; Python random
# class on host, Mersenne twister implementation on OT SW.
batch_prng_seed: 0
30 changes: 25 additions & 5 deletions capture/configs/ibex_sca_cw310.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ husky:
samling_rate: 200000000
num_segments: 20
num_cycles: 100
offset_cycles: 0
# Do not capture 100 nops that are inserted to give the trigger time to rise.
offset_cycles: 100
scope_gain: 27
capture:
scope_select: husky
Expand All @@ -22,7 +23,26 @@ capture:
trace_db: ot_trace_library
trace_threshold: 10000
test:
# which_test: ibex.sca.tl_write
# which_test: ibex.sca.tl_read
# which_test: ibex.sca.register_file_write
which_test: ibex.sca.register_file_read
# which_test: ibex_sca_tl_write_batch_fvsr
# which_test: ibex_sca_tl_write_batch_fvsr_fix_address
# which_test: ibex_sca_tl_write_batch_random
# which_test: ibex_sca_tl_write_batch_random_fix_address
# which_test: ibex_sca_tl_write_fvsr
# which_test: ibex_sca_tl_write_random
# which_test: ibex_sca_tl_read_batch_fvsr
# which_test: ibex_sca_tl_read_batch_fvsr_fix_address
# which_test: ibex_sca_tl_read_batch_random
# which_test: ibex_sca_tl_read_batch_random_fix_address
# which_test: ibex_sca_tl_read_fvsr
# which_test: ibex_sca_tl_read_random
# which_test: ibex_sca_register_file_write_batch_fvsr
# which_test: ibex_sca_register_file_write_batch_random
# which_test: ibex_sca_register_file_write_fvsr
# which_test: ibex_sca_register_file_write_random
# which_test: ibex_sca_register_file_read_batch_fvsr
# which_test: ibex_sca_register_file_read_batch_random
# which_test: ibex_sca_register_file_read_fvsr
which_test: ibex_sca_register_file_read_random
# seed for PRNG to generate sequence of plaintexts and keys; Python random
# class on host, Mersenne twister implementation on OT SW.
batch_prng_seed: 0
13 changes: 5 additions & 8 deletions ci/cfg/ci_ibex_sca_cw310_ujson.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@ target:
port: "/dev/ttyACM_CW310_1"
husky:
samling_rate: 200000000
num_segments: 20
num_cycles: 100
offset_cycles: 0
num_segments: 1
num_cycles: 50
offset_cycles: 100
scope_gain: 27
capture:
scope_select: husky
num_traces: 100
num_traces: 40
show_plot: True
plot_traces: 20
trace_db: ot_trace_library
trace_threshold: 10000
test:
# which_test: ibex.sca.tl_write
# which_test: ibex.sca.tl_read
# which_test: ibex.sca.register_file_write
which_test: ibex.sca.register_file_read
which_test: ibex_sca_register_file_read_random
4 changes: 2 additions & 2 deletions objs/sca_ujson_fpga_cw310.bin
Git LFS file not shown
Loading

0 comments on commit 756001c

Please sign in to comment.