Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aa953b9

Browse files
committedMar 22, 2024
[capture] Enable uJSON for OTBN
This commit enables communication with the OTBN SCA code over uJSON. The device code is located in lowRISC/opentitan#22190. Signed-off-by: Pascal Nasahl <nasahlpa@lowrisc.org>
1 parent c4575d2 commit aa953b9

10 files changed

+458
-71
lines changed
 

‎.github/workflows/fpga.yml

+59
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,65 @@ jobs:
148148
name: traces_sha3_random_cw310_ujson
149149
path: ./ci/projects/sha3_sca_random_cw310_ujson.html
150150

151+
otbn_sca_capture_cw310:
152+
name: Capture OTBN SCA traces (CW310)
153+
runs-on: [ubuntu-22.04-fpga, cw310]
154+
timeout-minutes: 30
155+
156+
steps:
157+
- uses: actions/checkout@v4
158+
with:
159+
lfs: true
160+
161+
- name: Install python dependencies
162+
run: |
163+
python3 -m pip install --user -r python-requirements.txt
164+
mkdir -p ci/projects
165+
166+
- name: Capture OTBN Vertical Keygen traces (simpleserial)
167+
working-directory: ci
168+
run: |
169+
../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_keygen_cw310_simpleserial.yaml -p projects/otbn_sca_vertical_keygen_cw310_simpleserial
170+
171+
- name: Upload OTBN Vertical Keygen traces (simpleserial)
172+
uses: actions/upload-artifact@v4
173+
with:
174+
name: traces_otbn_sca_vertical_keygen_cw310_simpleserial
175+
path: ./ci/projects/otbn_sca_vertical_keygen_cw310_simpleserial.html
176+
177+
- name: Capture OTBN Vertical Keygen traces (ujson)
178+
working-directory: ci
179+
run: |
180+
../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_keygen_cw310_ujson.yaml -p projects/otbn_sca_vertical_keygen_cw310_ujson
181+
182+
- name: Upload OTBN Vertical Keygen traces (ujson)
183+
uses: actions/upload-artifact@v4
184+
with:
185+
name: traces_otbn_sca_vertical_keygen_cw310_ujson
186+
path: ./ci/projects/otbn_sca_vertical_keygen_cw310_ujson.html
187+
188+
- name: Capture OTBN Vertical Modinv traces (simpleserial)
189+
working-directory: ci
190+
run: |
191+
../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_modinv_cw310_simpleserial.yaml -p projects/otbn_sca_vertical_modinv_cw310_simpleserial
192+
193+
- name: Upload OTBN Vertical Modinv traces (simpleserial)
194+
uses: actions/upload-artifact@v4
195+
with:
196+
name: traces_otbn_sca_vertical_modinv_cw310_simpleserial
197+
path: ./ci/projects/otbn_sca_vertical_modinv_cw310_simpleserial.html
198+
199+
- name: Capture OTBN Vertical Modinv traces (ujson)
200+
working-directory: ci
201+
run: |
202+
../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_modinv_cw310_ujson.yaml -p projects/otbn_sca_vertical_modinv_cw310_ujson
203+
204+
- name: Upload OTBN Vertical Modinv traces (ujson)
205+
uses: actions/upload-artifact@v4
206+
with:
207+
name: traces_otbn_sca_vertical_modinv_cw310_ujson
208+
path: ./ci/projects/otbn_sca_vertical_modinv_cw310_ujson.html
209+
151210
sca_capture_cw305:
152211
name: Capture AES SCA traces (CW305)
153212
runs-on: [ubuntu-22.04-fpga, cw305]

‎capture/capture_otbn.py

+22-20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import util.helpers as helpers
2424
from target.communication.sca_otbn_commands import OTOTBNVERT
25+
from target.communication.sca_prng_commands import OTPRNG
2526
from target.communication.sca_trigger_commands import OTTRIGGER
2627
from target.targets import Target, TargetConfig
2728
from util import check_version
@@ -191,39 +192,45 @@ def establish_communication(target, capture_cfg: CaptureConfig):
191192
192193
Returns:
193194
ot_otbn_vert: The communication interface to the OTBN app.
195+
ot_prng: The communication interface to the PRNG SCA application.
194196
ot_trig: The communication interface to the SCA trigger.
195197
"""
196198
# Create communication interface to OTBN.
197199
ot_otbn_vert = OTOTBNVERT(target=target, protocol=capture_cfg.protocol)
198200

201+
# Create communication interface to OT PRNG.
202+
ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol)
203+
199204
# Create communication interface to SCA trigger.
200205
ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol)
201206

202-
return ot_otbn_vert, ot_trig
207+
return ot_otbn_vert, ot_prng, ot_trig
203208

204209

205-
def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig,
206-
ot_otbn_vert) -> OTOTBNVERT:
210+
def configure_cipher(cfg: dict, capture_cfg: CaptureConfig, ot_otbn_vert,
211+
ot_prng) -> OTOTBNVERT:
207212
""" Configure the OTBN app.
208213
209214
Establish communication with the OTBN keygen app and configure the seed.
210215
211216
Args:
212217
cfg: The configuration for the current experiment.
213-
target: The OT target.
214218
curve_cfg: The curve config.
215219
capture_cfg: The configuration of the capture.
216220
ot_otbn_vert: The communication interface to the OTBN app.
221+
ot_prng: The communication interface to the PRNG SCA application.
217222
218223
Returns:
219224
curve_cfg: The curve configuration values.
220225
"""
226+
# Initialize OTBN on the target.
227+
ot_otbn_vert.init()
228+
221229
# Seed host's PRNG.
222230
random.seed(cfg["test"]["batch_prng_seed"])
223231

224232
# Seed the target's PRNGs
225-
ot_otbn_vert.write_batch_prng_seed(cfg["test"]["batch_prng_seed"].to_bytes(
226-
4, "little"))
233+
ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little"))
227234

228235
# select the otbn app on the device (0 -> keygen, 1 -> modinv)
229236
ot_otbn_vert.choose_otbn_app(cfg["test"]["app"])
@@ -474,12 +481,7 @@ def check_ciphertext_keygen(ot_otbn_vert: OTOTBNVERT, expected_key,
474481
"""
475482
# Read the output, unmask the key, and check if it matches
476483
# expectations.
477-
share0 = ot_otbn_vert.read_output(curve_cfg.seed_bytes)
478-
share1 = ot_otbn_vert.read_output(curve_cfg.seed_bytes)
479-
if share0 is None:
480-
raise RuntimeError('Random share0 is none')
481-
if share1 is None:
482-
raise RuntimeError('Random share1 is none')
484+
share0, share1 = ot_otbn_vert.read_seeds(curve_cfg.seed_bytes)
483485

484486
d0 = int.from_bytes(share0, byteorder='little')
485487
d1 = int.from_bytes(share1, byteorder='little')
@@ -505,8 +507,7 @@ def check_ciphertext_modinv(ot_otbn_vert: OTOTBNVERT, expected_output,
505507
actual_output: The received output of the modinv operation.
506508
"""
507509
# Read the output, unmask it, and check if it matches expectations.
508-
kalpha_inv = ot_otbn_vert.read_output(curve_cfg.key_bytes)
509-
alpha = ot_otbn_vert.read_output(curve_cfg.modinv_mask_bytes)
510+
kalpha_inv, alpha = ot_otbn_vert.read_alpha(curve_cfg.key_bytes, curve_cfg.modinv_mask_bytes)
510511
if kalpha_inv is None:
511512
raise RuntimeError('kaplpha_inv is none')
512513
if alpha is None:
@@ -589,8 +590,8 @@ def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT,
589590

590591
# Store trace into database.
591592
project.append_trace(wave=waves[0, :],
592-
plaintext=mask,
593-
ciphertext=share0 + share1,
593+
plaintext=bytearray(mask),
594+
ciphertext=bytearray(share0 + share1),
594595
key=seed_used)
595596

596597
# Memory allocation optimization for CW trace library.
@@ -660,11 +661,11 @@ def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT,
660661

661662
# Store trace into database.
662663
project.append_trace(wave=waves[0, :],
663-
plaintext=k_used,
664+
plaintext=bytearray(k_used),
664665
ciphertext=bytearray(
665666
actual_output.to_bytes(
666667
curve_cfg.key_bytes, 'little')),
667-
key=k_used)
668+
key=bytearray(k_used))
668669

669670
# Memory allocation optimization for CW trace library.
670671
num_segments_storage = project.optimize_capture(
@@ -729,6 +730,7 @@ def main(argv=None):
729730
key_len_bytes=cfg["test"]["key_len_bytes"],
730731
text_len_bytes=cfg["test"]["text_len_bytes"],
731732
protocol=cfg["target"]["protocol"],
733+
port = cfg["target"].get("port"),
732734
C=bytearray(),
733735
seed_fixed=bytearray(),
734736
expected_fixed_key=bytearray(),
@@ -739,10 +741,10 @@ def main(argv=None):
739741
)
740742

741743
# Open communication with target.
742-
ot_otbn_vert, ot_trig = establish_communication(target, capture_cfg)
744+
ot_otbn_vert, ot_prng, ot_trig = establish_communication(target, capture_cfg)
743745

744746
# Configure cipher.
745-
curve_cfg = configure_cipher(cfg, target, capture_cfg, ot_otbn_vert)
747+
curve_cfg = configure_cipher(cfg, capture_cfg, ot_otbn_vert, ot_prng)
746748

747749
# Configure trigger source.
748750
# 0 for HW, 1 for SW.

‎capture/configs/otbn_vertical_keygen_sca_cw310.yaml

+7-6
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,31 @@ target:
22
target_type: cw310
33
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
44
force_program_bitstream: True
5-
fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
5+
# fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
6+
fw_bin: ../objs/sca_ujson_fpga_cw310.bin
67
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
78
target_clk_mult: 0.24
89
target_freq: 24000000
910
baudrate: 115200
1011
output_len_bytes: 40
11-
protocol: "simpleserial"
12-
# protocol: "ujson"
13-
# port: "/dev/ttyACM4"
12+
# protocol: "simpleserial"
13+
protocol: "ujson"
14+
port: "/dev/ttyACM4"
1415
# Trigger source.
1516
# hw: Precise, hardware-generated trigger - FPGA only.
1617
# sw: Fully software-controlled trigger.
1718
trigger: "hw"
1819
husky:
1920
sampling_rate: 200000000
20-
num_segments: 20
21+
num_segments: 1
2122
num_cycles: 200
2223
offset_cycles: 0
2324
scope_gain: 24
2425
adc_mul: 1
2526
decimate: 1
2627
waverunner:
2728
waverunner_ip: 100.107.71.10
28-
num_segments: 20
29+
num_segments: 1
2930
num_samples: 6000
3031
sample_offset: 0
3132
capture:

‎capture/configs/otbn_vertical_modinv_sca_cw310.yaml

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ target:
22
target_type: cw310
33
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
44
force_program_bitstream: True
5-
fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
5+
# fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
6+
fw_bin: ../objs/sca_ujson_fpga_cw310.bin
67
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
78
target_clk_mult: 0.24
89
target_freq: 24000000
910
baudrate: 115200
1011
output_len_bytes: 40
11-
protocol: "simpleserial"
12-
# protocol: "ujson"
13-
# port: "/dev/ttyACM4"
12+
# protocol: "simpleserial"
13+
protocol: "ujson"
14+
port: "/dev/ttyACM4"
1415
# Trigger source.
1516
# hw: Precise, hardware-generated trigger - FPGA only.
1617
# sw: Fully software-controlled trigger.
17-
trigger: "hw"
18+
trigger: "sw"
1819
husky:
1920
sampling_rate: 200000000
2021
num_segments: 20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
target:
2+
target_type: cw310
3+
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
4+
force_program_bitstream: False
5+
fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
6+
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
7+
target_clk_mult: 0.24
8+
target_freq: 24000000
9+
baudrate: 115200
10+
output_len_bytes: 40
11+
protocol: "simpleserial"
12+
# Trigger source.
13+
# hw: Precise, hardware-generated trigger - FPGA only.
14+
# sw: Fully software-controlled trigger.
15+
trigger: "hw"
16+
husky:
17+
sampling_rate: 200000000
18+
num_segments: 1
19+
num_cycles: 200
20+
offset_cycles: 0
21+
scope_gain: 24
22+
adc_mul: 1
23+
decimate: 1
24+
capture:
25+
scope_select: husky
26+
show_plot: True
27+
plot_traces: 10
28+
num_traces: 100
29+
trace_threshold: 10000
30+
trace_db: ot_trace_library
31+
test:
32+
batch_prng_seed: 6
33+
key_len_bytes: 40
34+
text_len_bytes: 40
35+
plain_text_len_bytes: 40
36+
masks_off: False
37+
# Currently, 'p256' is the only supported curve.
38+
curve: p256
39+
# Select the OTBN app to analyze. Currently available: 'keygen', 'modinv'
40+
app: keygen
41+
# For app = keygen: There are two fixed-vs-random test types, KEY and SEED
42+
# Currently batch-mode capture only works with SEED
43+
test_type: SEED
44+
batch_mode: False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
target:
2+
target_type: cw310
3+
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
4+
force_program_bitstream: False
5+
fw_bin: ../objs/sca_ujson_fpga_cw310.bin
6+
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
7+
target_clk_mult: 0.24
8+
target_freq: 24000000
9+
baudrate: 115200
10+
output_len_bytes: 40
11+
protocol: "ujson"
12+
port: "/dev/ttyACM_CW310_1"
13+
# Trigger source.
14+
# hw: Precise, hardware-generated trigger - FPGA only.
15+
# sw: Fully software-controlled trigger.
16+
trigger: "hw"
17+
husky:
18+
sampling_rate: 200000000
19+
num_segments: 1
20+
num_cycles: 200
21+
offset_cycles: 0
22+
scope_gain: 24
23+
adc_mul: 1
24+
decimate: 1
25+
capture:
26+
scope_select: husky
27+
show_plot: True
28+
plot_traces: 10
29+
num_traces: 100
30+
trace_threshold: 10000
31+
trace_db: ot_trace_library
32+
test:
33+
batch_prng_seed: 6
34+
key_len_bytes: 40
35+
text_len_bytes: 40
36+
plain_text_len_bytes: 40
37+
masks_off: False
38+
# Currently, 'p256' is the only supported curve.
39+
curve: p256
40+
# Select the OTBN app to analyze. Currently available: 'keygen', 'modinv'
41+
app: keygen
42+
# For app = keygen: There are two fixed-vs-random test types, KEY and SEED
43+
# Currently batch-mode capture only works with SEED
44+
test_type: SEED
45+
batch_mode: False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
target:
2+
target_type: cw310
3+
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
4+
force_program_bitstream: False
5+
fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin"
6+
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
7+
target_clk_mult: 0.24
8+
target_freq: 24000000
9+
baudrate: 115200
10+
output_len_bytes: 40
11+
protocol: "simpleserial"
12+
# Trigger source.
13+
# hw: Precise, hardware-generated trigger - FPGA only.
14+
# sw: Fully software-controlled trigger.
15+
trigger: "sw"
16+
husky:
17+
sampling_rate: 200000000
18+
num_segments: 20
19+
num_cycles: 1000
20+
offset_cycles: 0
21+
scope_gain: 24
22+
adc_mul: 1
23+
decimate: 1
24+
capture:
25+
scope_select: husky
26+
show_plot: True
27+
plot_traces: 10
28+
num_traces: 100
29+
trace_threshold: 10000
30+
trace_db: ot_trace_library
31+
test:
32+
batch_prng_seed: 6
33+
key_len_bytes: 40
34+
text_len_bytes: 40
35+
plain_text_len_bytes: 40
36+
masks_off: False
37+
# Currently, 'p256' is the only supported curve.
38+
curve: p256
39+
# Select the OTBN app to analyze. Currently available: 'keygen', 'modinv'
40+
app: modinv
41+
# For app = keygen: There are two fixed-vs-random test types, KEY and SEED
42+
# Currently batch-mode capture only works with SEED
43+
test_type: SEED
44+
batch_mode: False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
target:
2+
target_type: cw310
3+
fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit"
4+
force_program_bitstream: False
5+
fw_bin: ../objs/sca_ujson_fpga_cw310.bin
6+
# target_clk_mult is a hardcoded value in the bitstream. Do not change.
7+
target_clk_mult: 0.24
8+
target_freq: 24000000
9+
baudrate: 115200
10+
output_len_bytes: 40
11+
protocol: "ujson"
12+
port: "/dev/ttyACM_CW310_1"
13+
# Trigger source.
14+
# hw: Precise, hardware-generated trigger - FPGA only.
15+
# sw: Fully software-controlled trigger.
16+
trigger: "sw"
17+
husky:
18+
sampling_rate: 200000000
19+
num_segments: 20
20+
num_cycles: 1000
21+
offset_cycles: 0
22+
scope_gain: 24
23+
adc_mul: 1
24+
decimate: 1
25+
capture:
26+
scope_select: husky
27+
show_plot: True
28+
plot_traces: 10
29+
num_traces: 100
30+
trace_threshold: 10000
31+
trace_db: ot_trace_library
32+
test:
33+
batch_prng_seed: 6
34+
key_len_bytes: 40
35+
text_len_bytes: 40
36+
plain_text_len_bytes: 40
37+
masks_off: False
38+
# Currently, 'p256' is the only supported curve.
39+
curve: p256
40+
# Select the OTBN app to analyze. Currently available: 'keygen', 'modinv'
41+
app: modinv
42+
# For app = keygen: There are two fixed-vs-random test types, KEY and SEED
43+
# Currently batch-mode capture only works with SEED
44+
test_type: SEED
45+
batch_mode: False

‎objs/sca_ujson_fpga_cw310.bin

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:b79fa7125b748b00bc231ecb563e266edf4213eb27ef2318b35315d5c32169b1
3-
size 304188
2+
oid sha256:435a989c52dcde6cc2d0cf3b5ffbb1eac4d499c9964d1ce44e5a30ba279ad510
3+
size 326668

‎target/communication/sca_otbn_commands.py

+184-38
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
Communication with OpenTitan either happens over simpleserial or the uJson
77
command interface.
88
"""
9+
import json
10+
import time
11+
from typing import Optional
912

1013

1114
class OTOTBNVERT:
@@ -15,93 +18,236 @@ def __init__(self, target, protocol: str) -> None:
1518
if protocol == "ujson":
1619
self.simple_serial = False
1720

21+
def _ujson_otbn_sca_cmd(self):
22+
# TODO: without the delay, the device uJSON command handler program
23+
# does not recognize the commands. Tracked in issue #256.
24+
time.sleep(0.01)
25+
self.target.write(json.dumps("OtbnSca").encode("ascii"))
26+
27+
def init(self):
28+
""" Initializes OTBN on the target.
29+
"""
30+
if not self.simple_serial:
31+
# OtbnSca command.
32+
self._ujson_otbn_sca_cmd()
33+
# Init command.
34+
self.target.write(json.dumps("Init").encode("ascii"))
35+
1836
def choose_otbn_app(self, app):
1937
""" Select the OTBN application.
2038
Args:
2139
app: OTBN application
2240
"""
41+
# Select the otbn app on the device (0 -> keygen, 1 -> modinv).
42+
app_value = 0x00
43+
if app == 'modinv':
44+
app_value = 0x01
2345
if self.simple_serial:
24-
# Select the otbn app on the device (0 -> keygen, 1 -> modinv).
25-
if app == 'keygen':
26-
self.target.write(cmd="a", data=bytearray([0x00]))
27-
if app == 'modinv':
28-
self.target.write(cmd="a", data=bytearray([0x01]))
29-
30-
def write_batch_prng_seed(self, seed):
31-
""" Seed the PRNG.
32-
Args:
33-
seed: The 4-byte seed.
34-
"""
35-
if self.simple_serial:
36-
self.target.write(cmd="s", data=seed)
46+
self.target.write(cmd="a", data=bytearray([app_value]))
47+
else:
48+
# OtbnSca command.
49+
self._ujson_otbn_sca_cmd()
50+
# Ecc256AppSelect command.
51+
self.target.write(json.dumps("Ecc256AppSelect").encode("ascii"))
52+
# App payload.
53+
time.sleep(0.01)
54+
app_select = {"app": [app_value]}
55+
self.target.write(json.dumps(app_select).encode("ascii"))
56+
time.sleep(0.01)
3757

38-
def write_keygen_seed(self, seed):
58+
def write_keygen_seed(self, seed, seed_length: Optional[int] = 40):
3959
""" Write the seed used for the keygen app.
4060
Args:
41-
seed: byte array containing the seed.
61+
seed: Byte array containing the seed.
62+
seed_length: The length of the seed.
4263
"""
4364
if self.simple_serial:
4465
self.target.write(cmd='x', data=seed)
66+
else:
67+
# OtbnSca command.
68+
self._ujson_otbn_sca_cmd()
69+
# Ecc256SetSeed command.
70+
time.sleep(0.01)
71+
self.target.write(json.dumps("Ecc256SetSeed").encode("ascii"))
72+
# Seed payload.
73+
time.sleep(0.01)
74+
seed_int = [x for x in seed]
75+
seed_data = {"seed": seed_int}
76+
self.target.write(json.dumps(seed_data).encode("ascii"))
4577

46-
def write_keygen_key_constant_redundancy(self, const):
78+
def write_keygen_key_constant_redundancy(self, const, const_length: Optional[int] = 40):
4779
""" Write the constant redundancy value for the keygen app.
4880
Args:
49-
seed: byte array containing the redundancy value.
81+
const: Byte array containing the redundancy value.
82+
const_length: The length of the constant.
5083
"""
5184
if self.simple_serial:
5285
self.target.write(cmd="c", data=const)
86+
else:
87+
# OtbnSca command.
88+
self._ujson_otbn_sca_cmd()
89+
# Ecc256SetC command.
90+
self.target.write(json.dumps("Ecc256SetC").encode("ascii"))
91+
# Constant payload.
92+
time.sleep(0.01)
93+
const_int = [x for x in const]
94+
const_data = {"constant": const_int, "constant_len": const_length}
95+
self.target.write(json.dumps(const_data).encode("ascii"))
5396

5497
def config_keygen_masking(self, off):
5598
""" Disable/enable masking.
5699
Args:
57-
off: boolean value.
100+
off: Boolean value.
58101
"""
102+
# Enable/disable masking.
103+
off_int = 0x01
104+
if off is True:
105+
off_int = 0x00
59106
if self.simple_serial:
60-
# Enable/disable masking.
61-
if off is True:
62-
self.target.write(cmd="m", data=bytearray([0x00]))
63-
else:
64-
self.target.write(cmd="m", data=bytearray([0x01]))
107+
self.target.write(cmd="m", data=bytearray([off_int]))
108+
else:
109+
# OtbnSca command.
110+
self._ujson_otbn_sca_cmd()
111+
# Ecc256EnMasks command.
112+
self.target.write(json.dumps("Ecc256EnMasks").encode("ascii"))
113+
# Enable/disable masks payload.
114+
time.sleep(0.01)
115+
mask = {"en_masks": [off_int]}
116+
self.target.write(json.dumps(mask).encode("ascii"))
65117

66118
def start_keygen(self, mask):
67119
""" Write the seed mask and start the keygen app.
68120
Args:
69-
mask: byte array containing the mask value.
121+
mask: Byte array containing the mask value.
70122
"""
71123
if self.simple_serial:
72124
# Send the mask and start the keygen operation.
73-
self.target.write('k', mask)
125+
self.target.write(cmd='k', data=mask)
126+
else:
127+
# OtbnSca command.
128+
self._ujson_otbn_sca_cmd()
129+
# Ecc256EcdsaSecretKeygen command.
130+
self.target.write(json.dumps("Ecc256EcdsaSecretKeygen").encode("ascii"))
131+
# Mask payload.
132+
time.sleep(0.01)
133+
mask_int = [x for x in mask]
134+
mask_data = {"mask": mask_int[0:20]}
135+
self.target.write(json.dumps(mask_data).encode("ascii"))
136+
time.sleep(0.01)
137+
mask_data = {"mask": mask_int[20:41]}
138+
self.target.write(json.dumps(mask_data).encode("ascii"))
74139

75-
def start_modinv(self, scalar_k0, scalar_k1):
140+
def start_modinv(self, scalar_k0, scalar_k1, k_length: Optional[int] = 80):
76141
""" Write the two scalar shares and start the modinv app.
77142
Args:
78-
scalar_k0: byte array containing the first scalar share.
79-
scalar_k1: byte array containing the second scalar share.
143+
scalar_k0: Byte array containing the first scalar share.
144+
scalar_k1: Byte array containing the second scalar share.
145+
k_length: The length of the scalar shares.
80146
"""
81147
if self.simple_serial:
82148
# Start modinv device computation.
83-
self.target.write('q', scalar_k0 + scalar_k1)
149+
self.target.write(cmd='q', data=(scalar_k0 + scalar_k1))
150+
else:
151+
# OtbnSca command.
152+
self._ujson_otbn_sca_cmd()
153+
# Ecc256Modinv command.
154+
self.target.write(json.dumps("Ecc256Modinv").encode("ascii"))
155+
# Scalar payload.
156+
time.sleep(0.01)
157+
scalar_int = [x for x in (scalar_k0 + scalar_k1)]
158+
scalar_data = {"k": scalar_int[0:20]}
159+
self.target.write(json.dumps(scalar_data).encode("ascii"))
160+
time.sleep(0.01)
161+
scalar_data = {"k": scalar_int[20:40]}
162+
self.target.write(json.dumps(scalar_data).encode("ascii"))
163+
time.sleep(0.01)
164+
scalar_data = {"k": scalar_int[40:60]}
165+
self.target.write(json.dumps(scalar_data).encode("ascii"))
166+
time.sleep(0.01)
167+
scalar_data = {"k": scalar_int[60:80]}
168+
self.target.write(json.dumps(scalar_data).encode("ascii"))
84169

85170
def start_keygen_batch(self, test_type, num_segments):
86171
""" Start the keygen app in batch mode.
87172
Args:
88-
test_type: string selecting the test type (KEY or SEED).
89-
num_segments: number of keygen executions to perform.
173+
test_type: String selecting the test type (KEY or SEED).
174+
num_segments: Number of keygen executions to perform.
90175
"""
91-
if self.simple_serial:
92-
# Start batch keygen.
93-
if test_type == 'KEY':
176+
if test_type == 'KEY':
177+
if self.simple_serial:
178+
# Start batch keygen.
94179
self.target.write(cmd="e", data=num_segments)
95180
else:
181+
# OtbnSca command.
182+
self._ujson_otbn_sca_cmd()
183+
# Ecc256EcdsaKeygenFvsrKeyBatch command.
184+
self.target.write(json.dumps("Ecc256EcdsaKeygenFvsrKeyBatch").encode("ascii"))
185+
time.sleep(0.01)
186+
num_segments_data = {"num_traces": [x for x in num_segments]}
187+
self.target.write(json.dumps(num_segments_data).encode("ascii"))
188+
else:
189+
if self.simple_serial:
96190
self.target.write(cmd="b", data=num_segments)
191+
else:
192+
# OtbnSca command.
193+
self._ujson_otbn_sca_cmd()
194+
# Ecc256EcdsaKeygenFvsrSeedBatch command.
195+
self.target.write(json.dumps("Ecc256EcdsaKeygenFvsrSeedBatch").encode("ascii"))
196+
time.sleep(0.01)
197+
num_segments_data = {"num_traces": [x for x in num_segments]}
198+
self.target.write(json.dumps(num_segments_data).encode("ascii"))
97199

98-
def read_output(self, len_bytes):
99-
""" Read the output from whichever OTBN app.
200+
def read_alpha(self, kalpha_inv_length: int, alpha_length: int):
201+
""" Read alpha & kalpha_inv from the device.
100202
Args:
101-
len_bytes: Number of bytes to read.
203+
kalpha_inv_length: Number of bytes to read for kalpha_inv.
204+
alpha_length: Number of bytes to read for alpha.
205+
Returns:
206+
The received output.
207+
"""
208+
if self.simple_serial:
209+
kalpha_inv = self.target.read("r", kalpha_inv_length, ack=False)
210+
alpha = self.target.read("r", alpha_length, ack=False)
211+
return kalpha_inv, alpha
212+
else:
213+
while True:
214+
read_line = str(self.target.readline())
215+
if "RESP_OK" in read_line:
216+
json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0]
217+
try:
218+
kalpha_inv = json.loads(json_string)["alpha_inv"]
219+
alpha = json.loads(json_string)["alpha"]
220+
return kalpha_inv, alpha
221+
except Exception:
222+
pass # noqa: E302
102223

224+
def read_seeds(self, seed_bytes: int):
225+
""" Read d0 and d1 from the device.
226+
Args:
227+
seed_bytes: Number of bytes to read for kalpha_inv.
228+
alpha_length: Number of bytes to read for alpha.
103229
Returns:
104230
The received output.
105231
"""
106232
if self.simple_serial:
107-
return self.target.read("r", len_bytes, ack=False)
233+
share0 = self.target.read("r", seed_bytes, ack=False)
234+
share1 = self.target.read("r", seed_bytes, ack=False)
235+
if share0 is None:
236+
raise RuntimeError('Random share0 is none')
237+
if share1 is None:
238+
raise RuntimeError('Random share1 is none')
239+
240+
return share0, share1
241+
else:
242+
d0 = None
243+
d1 = None
244+
while True:
245+
read_line = str(self.target.readline())
246+
if "RESP_OK" in read_line:
247+
json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0]
248+
if "d0" in json_string:
249+
d0 = json.loads(json_string)["d0"]
250+
elif "d1" in json_string:
251+
d1 = json.loads(json_string)["d1"]
252+
if d0 is not None and d1 is not None:
253+
return d0, d1

0 commit comments

Comments
 (0)
Please sign in to comment.