diff --git a/.github/workflows/fpga.yml b/.github/workflows/fpga.yml index 9d69b88d2..f9b37addc 100644 --- a/.github/workflows/fpga.yml +++ b/.github/workflows/fpga.yml @@ -148,6 +148,65 @@ jobs: name: traces_sha3_random_cw310_ujson path: ./ci/projects/sha3_sca_random_cw310_ujson.html + otbn_sca_capture_cw310: + name: Capture OTBN SCA traces (CW310) + runs-on: [ubuntu-22.04-fpga, cw310] + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - name: Install python dependencies + run: | + python3 -m pip install --user -r python-requirements.txt + mkdir -p ci/projects + + - name: Capture OTBN Vertical Keygen traces (simpleserial) + working-directory: ci + run: | + ../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_keygen_cw310_simpleserial.yaml -p projects/otbn_sca_vertical_keygen_cw310_simpleserial + + - name: Upload OTBN Vertical Keygen traces (simpleserial) + uses: actions/upload-artifact@v4 + with: + name: traces_otbn_sca_vertical_keygen_cw310_simpleserial + path: ./ci/projects/otbn_sca_vertical_keygen_cw310_simpleserial.html + + - name: Capture OTBN Vertical Keygen traces (ujson) + working-directory: ci + run: | + ../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_keygen_cw310_ujson.yaml -p projects/otbn_sca_vertical_keygen_cw310_ujson + + - name: Upload OTBN Vertical Keygen traces (ujson) + uses: actions/upload-artifact@v4 + with: + name: traces_otbn_sca_vertical_keygen_cw310_ujson + path: ./ci/projects/otbn_sca_vertical_keygen_cw310_ujson.html + + - name: Capture OTBN Vertical Modinv traces (simpleserial) + working-directory: ci + run: | + ../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_modinv_cw310_simpleserial.yaml -p projects/otbn_sca_vertical_modinv_cw310_simpleserial + + - name: Upload OTBN Vertical Modinv traces (simpleserial) + uses: actions/upload-artifact@v4 + with: + name: traces_otbn_sca_vertical_modinv_cw310_simpleserial + path: ./ci/projects/otbn_sca_vertical_modinv_cw310_simpleserial.html + + - name: Capture OTBN Vertical Modinv traces (ujson) + working-directory: ci + run: | + ../capture/capture_otbn.py -c cfg/ci_otbn_sca_vertical_modinv_cw310_ujson.yaml -p projects/otbn_sca_vertical_modinv_cw310_ujson + + - name: Upload OTBN Vertical Modinv traces (ujson) + uses: actions/upload-artifact@v4 + with: + name: traces_otbn_sca_vertical_modinv_cw310_ujson + path: ./ci/projects/otbn_sca_vertical_modinv_cw310_ujson.html + sca_capture_cw305: name: Capture AES SCA traces (CW305) runs-on: [ubuntu-22.04-fpga, cw305] diff --git a/capture/capture_otbn.py b/capture/capture_otbn.py index c399d4989..cf2f38498 100755 --- a/capture/capture_otbn.py +++ b/capture/capture_otbn.py @@ -22,6 +22,7 @@ import util.helpers as helpers from target.communication.sca_otbn_commands import OTOTBNVERT +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 @@ -191,39 +192,45 @@ def establish_communication(target, capture_cfg: CaptureConfig): Returns: ot_otbn_vert: The communication interface to the OTBN app. + ot_prng: The communication interface to the PRNG SCA application. ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OTBN. ot_otbn_vert = OTOTBNVERT(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_otbn_vert, ot_trig + return ot_otbn_vert, ot_prng, ot_trig -def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, - ot_otbn_vert) -> OTOTBNVERT: +def configure_cipher(cfg: dict, capture_cfg: CaptureConfig, ot_otbn_vert, + ot_prng) -> OTOTBNVERT: """ Configure the OTBN app. Establish communication with the OTBN keygen app and configure the seed. Args: cfg: The configuration for the current experiment. - target: The OT target. curve_cfg: The curve config. capture_cfg: The configuration of the capture. ot_otbn_vert: The communication interface to the OTBN app. + ot_prng: The communication interface to the PRNG SCA application. Returns: curve_cfg: The curve configuration values. """ + # Initialize OTBN on the target. + ot_otbn_vert.init() + # Seed host's PRNG. random.seed(cfg["test"]["batch_prng_seed"]) # Seed the target's PRNGs - ot_otbn_vert.write_batch_prng_seed(cfg["test"]["batch_prng_seed"].to_bytes( - 4, "little")) + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) # select the otbn app on the device (0 -> keygen, 1 -> modinv) ot_otbn_vert.choose_otbn_app(cfg["test"]["app"]) @@ -474,12 +481,7 @@ def check_ciphertext_keygen(ot_otbn_vert: OTOTBNVERT, expected_key, """ # Read the output, unmask the key, and check if it matches # expectations. - share0 = ot_otbn_vert.read_output(curve_cfg.seed_bytes) - share1 = ot_otbn_vert.read_output(curve_cfg.seed_bytes) - if share0 is None: - raise RuntimeError('Random share0 is none') - if share1 is None: - raise RuntimeError('Random share1 is none') + share0, share1 = ot_otbn_vert.read_seeds(curve_cfg.seed_bytes) d0 = int.from_bytes(share0, byteorder='little') d1 = int.from_bytes(share1, byteorder='little') @@ -505,8 +507,7 @@ def check_ciphertext_modinv(ot_otbn_vert: OTOTBNVERT, expected_output, actual_output: The received output of the modinv operation. """ # Read the output, unmask it, and check if it matches expectations. - kalpha_inv = ot_otbn_vert.read_output(curve_cfg.key_bytes) - alpha = ot_otbn_vert.read_output(curve_cfg.modinv_mask_bytes) + kalpha_inv, alpha = ot_otbn_vert.read_alpha(curve_cfg.key_bytes, curve_cfg.modinv_mask_bytes) if kalpha_inv is None: raise RuntimeError('kaplpha_inv is none') if alpha is None: @@ -589,8 +590,8 @@ def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT, # Store trace into database. project.append_trace(wave=waves[0, :], - plaintext=mask, - ciphertext=share0 + share1, + plaintext=bytearray(mask), + ciphertext=bytearray(share0 + share1), key=seed_used) # Memory allocation optimization for CW trace library. @@ -660,11 +661,11 @@ def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT, # Store trace into database. project.append_trace(wave=waves[0, :], - plaintext=k_used, + plaintext=bytearray(k_used), ciphertext=bytearray( actual_output.to_bytes( curve_cfg.key_bytes, 'little')), - key=k_used) + key=bytearray(k_used)) # Memory allocation optimization for CW trace library. num_segments_storage = project.optimize_capture( @@ -729,6 +730,7 @@ def main(argv=None): key_len_bytes=cfg["test"]["key_len_bytes"], text_len_bytes=cfg["test"]["text_len_bytes"], protocol=cfg["target"]["protocol"], + port = cfg["target"].get("port"), C=bytearray(), seed_fixed=bytearray(), expected_fixed_key=bytearray(), @@ -739,10 +741,10 @@ def main(argv=None): ) # Open communication with target. - ot_otbn_vert, ot_trig = establish_communication(target, capture_cfg) + ot_otbn_vert, ot_prng, ot_trig = establish_communication(target, capture_cfg) # Configure cipher. - curve_cfg = configure_cipher(cfg, target, capture_cfg, ot_otbn_vert) + curve_cfg = configure_cipher(cfg, capture_cfg, ot_otbn_vert, ot_prng) # Configure trigger source. # 0 for HW, 1 for SW. diff --git a/capture/configs/otbn_vertical_keygen_sca_cw310.yaml b/capture/configs/otbn_vertical_keygen_sca_cw310.yaml index 85dbe96ef..24d26a1c1 100644 --- a/capture/configs/otbn_vertical_keygen_sca_cw310.yaml +++ b/capture/configs/otbn_vertical_keygen_sca_cw310.yaml @@ -2,22 +2,23 @@ target: target_type: cw310 fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True - fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + # fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + fw_bin: ../objs/sca_ujson_fpga_cw310.bin # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 output_len_bytes: 40 - protocol: "simpleserial" - # protocol: "ujson" - # port: "/dev/ttyACM4" + # protocol: "simpleserial" + protocol: "ujson" + port: "/dev/ttyACM4" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 + num_segments: 1 num_cycles: 200 offset_cycles: 0 scope_gain: 24 @@ -25,7 +26,7 @@ husky: decimate: 1 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 + num_segments: 1 num_samples: 6000 sample_offset: 0 capture: diff --git a/capture/configs/otbn_vertical_modinv_sca_cw310.yaml b/capture/configs/otbn_vertical_modinv_sca_cw310.yaml index 2a54bc51d..a32301b83 100644 --- a/capture/configs/otbn_vertical_modinv_sca_cw310.yaml +++ b/capture/configs/otbn_vertical_modinv_sca_cw310.yaml @@ -2,19 +2,20 @@ target: target_type: cw310 fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True - fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + # fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + fw_bin: ../objs/sca_ujson_fpga_cw310.bin # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 output_len_bytes: 40 - protocol: "simpleserial" - # protocol: "ujson" - # port: "/dev/ttyACM4" + # protocol: "simpleserial" + protocol: "ujson" + port: "/dev/ttyACM4" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. - trigger: "hw" + trigger: "sw" husky: sampling_rate: 200000000 num_segments: 20 diff --git a/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_simpleserial.yaml b/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_simpleserial.yaml new file mode 100644 index 000000000..8cb5109da --- /dev/null +++ b/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_simpleserial.yaml @@ -0,0 +1,44 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + # target_clk_mult is a hardcoded value in the bitstream. Do not change. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 + output_len_bytes: 40 + protocol: "simpleserial" + # Trigger source. + # hw: Precise, hardware-generated trigger - FPGA only. + # sw: Fully software-controlled trigger. + trigger: "hw" +husky: + sampling_rate: 200000000 + num_segments: 1 + num_cycles: 200 + offset_cycles: 0 + scope_gain: 24 + adc_mul: 1 + decimate: 1 +capture: + scope_select: husky + show_plot: True + plot_traces: 10 + num_traces: 100 + trace_threshold: 10000 + trace_db: ot_trace_library +test: + batch_prng_seed: 6 + key_len_bytes: 40 + text_len_bytes: 40 + plain_text_len_bytes: 40 + masks_off: False + # Currently, 'p256' is the only supported curve. + curve: p256 + # Select the OTBN app to analyze. Currently available: 'keygen', 'modinv' + app: keygen + # For app = keygen: There are two fixed-vs-random test types, KEY and SEED + # Currently batch-mode capture only works with SEED + test_type: SEED + batch_mode: False \ No newline at end of file diff --git a/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_ujson.yaml b/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_ujson.yaml new file mode 100644 index 000000000..97259f7c7 --- /dev/null +++ b/ci/cfg/ci_otbn_sca_vertical_keygen_cw310_ujson.yaml @@ -0,0 +1,45 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: ../objs/sca_ujson_fpga_cw310.bin + # target_clk_mult is a hardcoded value in the bitstream. Do not change. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 + output_len_bytes: 40 + protocol: "ujson" + port: "/dev/ttyACM_CW310_1" + # Trigger source. + # hw: Precise, hardware-generated trigger - FPGA only. + # sw: Fully software-controlled trigger. + trigger: "hw" +husky: + sampling_rate: 200000000 + num_segments: 1 + num_cycles: 200 + offset_cycles: 0 + scope_gain: 24 + adc_mul: 1 + decimate: 1 +capture: + scope_select: husky + show_plot: True + plot_traces: 10 + num_traces: 100 + trace_threshold: 10000 + trace_db: ot_trace_library +test: + batch_prng_seed: 6 + key_len_bytes: 40 + text_len_bytes: 40 + plain_text_len_bytes: 40 + masks_off: False + # Currently, 'p256' is the only supported curve. + curve: p256 + # Select the OTBN app to analyze. Currently available: 'keygen', 'modinv' + app: keygen + # For app = keygen: There are two fixed-vs-random test types, KEY and SEED + # Currently batch-mode capture only works with SEED + test_type: SEED + batch_mode: False \ No newline at end of file diff --git a/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_simpleserial.yaml b/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_simpleserial.yaml new file mode 100644 index 000000000..5ff932818 --- /dev/null +++ b/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_simpleserial.yaml @@ -0,0 +1,44 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/otbn_vertical_serial_fpga_cw310.bin" + # target_clk_mult is a hardcoded value in the bitstream. Do not change. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 + output_len_bytes: 40 + protocol: "simpleserial" + # Trigger source. + # hw: Precise, hardware-generated trigger - FPGA only. + # sw: Fully software-controlled trigger. + trigger: "sw" +husky: + sampling_rate: 200000000 + num_segments: 20 + num_cycles: 1000 + offset_cycles: 0 + scope_gain: 24 + adc_mul: 1 + decimate: 1 +capture: + scope_select: husky + show_plot: True + plot_traces: 10 + num_traces: 100 + trace_threshold: 10000 + trace_db: ot_trace_library +test: + batch_prng_seed: 6 + key_len_bytes: 40 + text_len_bytes: 40 + plain_text_len_bytes: 40 + masks_off: False + # Currently, 'p256' is the only supported curve. + curve: p256 + # Select the OTBN app to analyze. Currently available: 'keygen', 'modinv' + app: modinv + # For app = keygen: There are two fixed-vs-random test types, KEY and SEED + # Currently batch-mode capture only works with SEED + test_type: SEED + batch_mode: False \ No newline at end of file diff --git a/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_ujson.yaml b/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_ujson.yaml new file mode 100644 index 000000000..289207c51 --- /dev/null +++ b/ci/cfg/ci_otbn_sca_vertical_modinv_cw310_ujson.yaml @@ -0,0 +1,45 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: ../objs/sca_ujson_fpga_cw310.bin + # target_clk_mult is a hardcoded value in the bitstream. Do not change. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 + output_len_bytes: 40 + protocol: "ujson" + port: "/dev/ttyACM_CW310_1" + # Trigger source. + # hw: Precise, hardware-generated trigger - FPGA only. + # sw: Fully software-controlled trigger. + trigger: "sw" +husky: + sampling_rate: 200000000 + num_segments: 20 + num_cycles: 1000 + offset_cycles: 0 + scope_gain: 24 + adc_mul: 1 + decimate: 1 +capture: + scope_select: husky + show_plot: True + plot_traces: 10 + num_traces: 100 + trace_threshold: 10000 + trace_db: ot_trace_library +test: + batch_prng_seed: 6 + key_len_bytes: 40 + text_len_bytes: 40 + plain_text_len_bytes: 40 + masks_off: False + # Currently, 'p256' is the only supported curve. + curve: p256 + # Select the OTBN app to analyze. Currently available: 'keygen', 'modinv' + app: modinv + # For app = keygen: There are two fixed-vs-random test types, KEY and SEED + # Currently batch-mode capture only works with SEED + test_type: SEED + batch_mode: False \ No newline at end of file diff --git a/objs/sca_ujson_fpga_cw310.bin b/objs/sca_ujson_fpga_cw310.bin index 7fb91096d..991bdc813 100644 --- a/objs/sca_ujson_fpga_cw310.bin +++ b/objs/sca_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b79fa7125b748b00bc231ecb563e266edf4213eb27ef2318b35315d5c32169b1 -size 304188 +oid sha256:435a989c52dcde6cc2d0cf3b5ffbb1eac4d499c9964d1ce44e5a30ba279ad510 +size 326668 diff --git a/target/communication/sca_otbn_commands.py b/target/communication/sca_otbn_commands.py index bf94ec2af..aa0b53e52 100644 --- a/target/communication/sca_otbn_commands.py +++ b/target/communication/sca_otbn_commands.py @@ -6,6 +6,9 @@ Communication with OpenTitan either happens over simpleserial or the uJson command interface. """ +import json +import time +from typing import Optional class OTOTBNVERT: @@ -15,93 +18,236 @@ def __init__(self, target, protocol: str) -> None: if protocol == "ujson": self.simple_serial = False + def _ujson_otbn_sca_cmd(self): + # TODO: without the delay, the device uJSON command handler program + # does not recognize the commands. Tracked in issue #256. + time.sleep(0.01) + self.target.write(json.dumps("OtbnSca").encode("ascii")) + + def init(self): + """ Initializes OTBN on the target. + """ + if not self.simple_serial: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Init command. + self.target.write(json.dumps("Init").encode("ascii")) + def choose_otbn_app(self, app): """ Select the OTBN application. Args: app: OTBN application """ + # Select the otbn app on the device (0 -> keygen, 1 -> modinv). + app_value = 0x00 + if app == 'modinv': + app_value = 0x01 if self.simple_serial: - # Select the otbn app on the device (0 -> keygen, 1 -> modinv). - if app == 'keygen': - self.target.write(cmd="a", data=bytearray([0x00])) - if app == 'modinv': - self.target.write(cmd="a", data=bytearray([0x01])) - - def write_batch_prng_seed(self, seed): - """ Seed the PRNG. - Args: - seed: The 4-byte seed. - """ - if self.simple_serial: - self.target.write(cmd="s", data=seed) + self.target.write(cmd="a", data=bytearray([app_value])) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256AppSelect command. + self.target.write(json.dumps("Ecc256AppSelect").encode("ascii")) + # App payload. + time.sleep(0.01) + app_select = {"app": [app_value]} + self.target.write(json.dumps(app_select).encode("ascii")) + time.sleep(0.01) - def write_keygen_seed(self, seed): + def write_keygen_seed(self, seed, seed_length: Optional[int] = 40): """ Write the seed used for the keygen app. Args: - seed: byte array containing the seed. + seed: Byte array containing the seed. + seed_length: The length of the seed. """ if self.simple_serial: self.target.write(cmd='x', data=seed) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256SetSeed command. + time.sleep(0.01) + self.target.write(json.dumps("Ecc256SetSeed").encode("ascii")) + # Seed payload. + time.sleep(0.01) + seed_int = [x for x in seed] + seed_data = {"seed": seed_int} + self.target.write(json.dumps(seed_data).encode("ascii")) - def write_keygen_key_constant_redundancy(self, const): + def write_keygen_key_constant_redundancy(self, const, const_length: Optional[int] = 40): """ Write the constant redundancy value for the keygen app. Args: - seed: byte array containing the redundancy value. + const: Byte array containing the redundancy value. + const_length: The length of the constant. """ if self.simple_serial: self.target.write(cmd="c", data=const) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256SetC command. + self.target.write(json.dumps("Ecc256SetC").encode("ascii")) + # Constant payload. + time.sleep(0.01) + const_int = [x for x in const] + const_data = {"constant": const_int, "constant_len": const_length} + self.target.write(json.dumps(const_data).encode("ascii")) def config_keygen_masking(self, off): """ Disable/enable masking. Args: - off: boolean value. + off: Boolean value. """ + # Enable/disable masking. + off_int = 0x01 + if off is True: + off_int = 0x00 if self.simple_serial: - # Enable/disable masking. - if off is True: - self.target.write(cmd="m", data=bytearray([0x00])) - else: - self.target.write(cmd="m", data=bytearray([0x01])) + self.target.write(cmd="m", data=bytearray([off_int])) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256EnMasks command. + self.target.write(json.dumps("Ecc256EnMasks").encode("ascii")) + # Enable/disable masks payload. + time.sleep(0.01) + mask = {"en_masks": [off_int]} + self.target.write(json.dumps(mask).encode("ascii")) def start_keygen(self, mask): """ Write the seed mask and start the keygen app. Args: - mask: byte array containing the mask value. + mask: Byte array containing the mask value. """ if self.simple_serial: # Send the mask and start the keygen operation. - self.target.write('k', mask) + self.target.write(cmd='k', data=mask) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256EcdsaSecretKeygen command. + self.target.write(json.dumps("Ecc256EcdsaSecretKeygen").encode("ascii")) + # Mask payload. + time.sleep(0.01) + mask_int = [x for x in mask] + mask_data = {"mask": mask_int[0:20]} + self.target.write(json.dumps(mask_data).encode("ascii")) + time.sleep(0.01) + mask_data = {"mask": mask_int[20:41]} + self.target.write(json.dumps(mask_data).encode("ascii")) - def start_modinv(self, scalar_k0, scalar_k1): + def start_modinv(self, scalar_k0, scalar_k1, k_length: Optional[int] = 80): """ Write the two scalar shares and start the modinv app. Args: - scalar_k0: byte array containing the first scalar share. - scalar_k1: byte array containing the second scalar share. + scalar_k0: Byte array containing the first scalar share. + scalar_k1: Byte array containing the second scalar share. + k_length: The length of the scalar shares. """ if self.simple_serial: # Start modinv device computation. - self.target.write('q', scalar_k0 + scalar_k1) + self.target.write(cmd='q', data=(scalar_k0 + scalar_k1)) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256Modinv command. + self.target.write(json.dumps("Ecc256Modinv").encode("ascii")) + # Scalar payload. + time.sleep(0.01) + scalar_int = [x for x in (scalar_k0 + scalar_k1)] + scalar_data = {"k": scalar_int[0:20]} + self.target.write(json.dumps(scalar_data).encode("ascii")) + time.sleep(0.01) + scalar_data = {"k": scalar_int[20:40]} + self.target.write(json.dumps(scalar_data).encode("ascii")) + time.sleep(0.01) + scalar_data = {"k": scalar_int[40:60]} + self.target.write(json.dumps(scalar_data).encode("ascii")) + time.sleep(0.01) + scalar_data = {"k": scalar_int[60:80]} + self.target.write(json.dumps(scalar_data).encode("ascii")) def start_keygen_batch(self, test_type, num_segments): """ Start the keygen app in batch mode. Args: - test_type: string selecting the test type (KEY or SEED). - num_segments: number of keygen executions to perform. + test_type: String selecting the test type (KEY or SEED). + num_segments: Number of keygen executions to perform. """ - if self.simple_serial: - # Start batch keygen. - if test_type == 'KEY': + if test_type == 'KEY': + if self.simple_serial: + # Start batch keygen. self.target.write(cmd="e", data=num_segments) else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256EcdsaKeygenFvsrKeyBatch command. + self.target.write(json.dumps("Ecc256EcdsaKeygenFvsrKeyBatch").encode("ascii")) + time.sleep(0.01) + num_segments_data = {"num_traces": [x for x in num_segments]} + self.target.write(json.dumps(num_segments_data).encode("ascii")) + else: + if self.simple_serial: self.target.write(cmd="b", data=num_segments) + else: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Ecc256EcdsaKeygenFvsrSeedBatch command. + self.target.write(json.dumps("Ecc256EcdsaKeygenFvsrSeedBatch").encode("ascii")) + time.sleep(0.01) + num_segments_data = {"num_traces": [x for x in num_segments]} + self.target.write(json.dumps(num_segments_data).encode("ascii")) - def read_output(self, len_bytes): - """ Read the output from whichever OTBN app. + def read_alpha(self, kalpha_inv_length: int, alpha_length: int): + """ Read alpha & kalpha_inv from the device. Args: - len_bytes: Number of bytes to read. + kalpha_inv_length: Number of bytes to read for kalpha_inv. + alpha_length: Number of bytes to read for alpha. + Returns: + The received output. + """ + if self.simple_serial: + kalpha_inv = self.target.read("r", kalpha_inv_length, ack=False) + alpha = self.target.read("r", alpha_length, ack=False) + return kalpha_inv, alpha + else: + while True: + read_line = str(self.target.readline()) + if "RESP_OK" in read_line: + json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] + try: + kalpha_inv = json.loads(json_string)["alpha_inv"] + alpha = json.loads(json_string)["alpha"] + return kalpha_inv, alpha + except Exception: + pass # noqa: E302 + def read_seeds(self, seed_bytes: int): + """ Read d0 and d1 from the device. + Args: + seed_bytes: Number of bytes to read for kalpha_inv. + alpha_length: Number of bytes to read for alpha. Returns: The received output. """ if self.simple_serial: - return self.target.read("r", len_bytes, ack=False) + share0 = self.target.read("r", seed_bytes, ack=False) + share1 = self.target.read("r", seed_bytes, ack=False) + if share0 is None: + raise RuntimeError('Random share0 is none') + if share1 is None: + raise RuntimeError('Random share1 is none') + + return share0, share1 + else: + d0 = None + d1 = None + while True: + read_line = str(self.target.readline()) + if "RESP_OK" in read_line: + json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] + if "d0" in json_string: + d0 = json.loads(json_string)["d0"] + elif "d1" in json_string: + d1 = json.loads(json_string)["d1"] + if d0 is not None and d1 is not None: + return d0, d1