diff --git a/.gitattributes b/.gitattributes index 34163813..9c1b0589 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,10 +2,14 @@ cw/objs/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit filter=lfs diff=lfs cw/objs/aes_serial_fpga_nexysvideo.bin filter=lfs diff=lfs merge=lfs -text cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit filter=lfs diff=lfs merge=lfs -text cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac_dom.bit filter=lfs diff=lfs merge=lfs -text +cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit filter=lfs diff=lfs merge=lfs -text cw/objs/kmac_serial_fpga_cw310.bin filter=lfs diff=lfs merge=lfs -text cw/objs/sha3_serial_fpga_cw310.bin filter=lfs diff=lfs merge=lfs -text cw/objs/aes_serial_fpga_cw310.bin filter=lfs diff=lfs merge=lfs -text +cw/objs/ecc_serial_fpga_cw310.bin filter=lfs diff=lfs merge=lfs -text +cw/objs/ecc384_serial_fpga_cw310.bin filter=lfs diff=lfs merge=lfs -text doc/img/cw310_cwhusky.jpg filter=lfs diff=lfs merge=lfs -text doc/img/sample_traces_aes.png filter=lfs diff=lfs merge=lfs -text doc/img/sample_traces_kmac.png filter=lfs diff=lfs merge=lfs -text test/data/tvla_general/* filter=lfs diff=lfs merge=lfs -text +doc/img/ot-sca-cw310-clocking.png filter=lfs diff=lfs merge=lfs -text diff --git a/cw/capture.py b/cw/capture.py index d569afb9..b5e50e6f 100755 --- a/cw/capture.py +++ b/cw/capture.py @@ -991,6 +991,70 @@ def kmac_fvsr_key_batch(ctx: typer.Context, capture_end(ctx.obj.cfg) +def capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, secret_k, priv_key_d, msg): + """ A utility function to collect the full OTBN trace section by section + + ECDSA is a long operation (e.g, ECDSA-256 takes ~7M samples) that doesn't fit + into the 130k-sample trace buffer of CW-Husky. This function allows us + to collect the full ECDSA trace section by section. + + Args: + ot: Initialized OpenTitan target. + fw_bin: ECDSA binary. + pll_frequency: Output frequency of the FPGA PLL. + To capture the long OTBN operations, + we need to use different frequency than 100MHz + num_sections: number of traces sections to collect + ECDSA is executed num_sections times + At each execution a different offset value is used + secret_k: ephemeral secret k + priv_key_d: private key d + msg: message to be signed + + """ + + # This determines if we want to reprogram the firmware before every sign operation + # The default value is false. + reset_firmware = False + + # Create a temporary buffer to keep the collected sections + tmp_buffer = np.array([]) + for ii in range(num_sections): + if reset_firmware: + ot.program_target(fw_bin, pll_frequency) + + # For each section ii, set the adc_offset parameter accordingly + ot.scope.adc.offset = ii * 131070 + + # Optional commands to overwrite the default values declared in the C code. + ot.target.simpleserial_write('d', priv_key_d) + # Message to sign + ot.target.simpleserial_write('n', msg) + # Send the ephemeral secret k and trigger the signature geneartion + ot.target.simpleserial_write('k', secret_k) + + # Arm the scope + ot.scope.arm() + + # Start the ECDSA operation + ot.target.simpleserial_write('p', bytearray([0x01])) + + # Wait until operation is done + ret = ot.scope.capture(poll_done=True) + # If getting inconsistent results (e.g. variable number of cycles), + # adding a sufficient sleep below here appears to fix things + time.sleep(1) + if ret: + raise RuntimeError('Timeout during capture') + # Check the number of cycles, where the trigger signal was high + cycles = ot.scope.adc.trig_count + print("Observed number of cycles: %d" % cycles) + + # Append the section into the waves array + tmp_buffer = np.append(tmp_buffer, ot.scope.get_last_trace(as_int=True)) + return tmp_buffer + + def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): """An example capture loop to capture OTBN-ECDSA-256/384 traces. @@ -999,22 +1063,17 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): Allows a user to set the ephemeral secret scalar k, private key d, and message msg. For the corresponding driver, check - /sw/device/ecc384_serial.c + /sw/device/ecc_serial.c Args: ot: Initialized OpenTitan target. - fw_bin: Key and plaintext generator. + fw_bin: ECDSA binary. pll_frequency: Output frequency of the FPGA PLL. To capture the long OTBN operations, we may need to use different frequency than 100MHz capture_cfg: Capture configuration from the yaml file """ - # Currently, we need to reprogram the firmware before every sign operation - # TODO: Investigate the C code (ecc384_serial) to check if we can run multiple - # signing operations without reloading the firmware. - reset_firmware = True - # Be sure we don't use the stream mode if ot.scope._is_husky: ot.scope.adc.stream_mode = False @@ -1039,80 +1098,91 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): # Loop to collect each power trace for _ in tqdm(range(capture_cfg["num_traces"]), desc='Capturing', ncols=80): - # create a clean array to keep each section + + # This part can be modified to create a new command. + # For example, a random secret scalar can be set using the following + # from numpy.random import default_rng + # rng = default_rng() + # secret_k0 = bytearray(rng.bytes(32)) + # secret_k1 = bytearray(rng.bytes(32)) + msg = "Hello OTBN.".encode() + # ECDSA-384 + if capture_cfg["key_len_bytes"] == 48: + # Set two shares of the private key d + priv_key_d0 = bytearray([ + 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, + 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, + 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA, + 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8, + 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, + 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 + ]) + priv_key_d1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # Set two shares of the scalar secret_k + secret_k0 = bytearray([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + secret_k1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # ECDSA-256 + elif capture_cfg["key_len_bytes"] == 32: + # Set two shares of the private key d + priv_key_d0 = bytearray([ + 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, + 0x02, 0x0c, 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, + 0x0c, 0xf0, 0x18, 0x0d, 0xf4, 0x6c, 0x0b, 0xda, + 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, 0x45, 0x55 + ]) + priv_key_d1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # Set two shares of the scalar secret_k + secret_k0 = bytearray([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + secret_k1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + else: + raise RuntimeError('priv_key_d must be either 32B or 48B') + + # Combine the two shares of d and k + priv_key_d = priv_key_d0 + priv_key_d1 + secret_k = secret_k0 + secret_k1 + + # Create a clean array to keep the collected traces waves = np.array([]) - # Loop to collect each section of the power trace - for ii in range(num_sections): - # Currently, we have to reload the firmware to be able to send a - # new signing command - # TODO: Investigate how we can solve this - if reset_firmware: - ot.program_target(fw_bin, pll_frequency) - - # For each section ii, set the adc_offset parameter accordingly - ot.scope.adc.offset = ii * 131070 - - # Optional commands to overwrite the default values of the private key d, - # and the message msg. - # The current values are set to the default values in the C code (ecc384_serial.c) - if capture_cfg["key_len_bytes"] == 48: - priv_key_d = bytearray([ - 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, 0x05, 0xB1, - 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, 0xE2, 0x3C, 0x3B, 0x66, - 0x7B, 0xF2, 0x97, 0xBA, 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, - 0x37, 0xD8, 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, - 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 - ]) - elif capture_cfg["key_len_bytes"] == 32: - priv_key_d = bytearray([ - 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, 0x02, 0x0c, - 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, 0x0c, 0xf0, 0x18, 0x0d, - 0xf4, 0x6c, 0x0b, 0xda, 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, - 0x45, 0x55 - ]) - else: - raise RuntimeError('priv_key_d must be either 32B or 48B') - ot.target.simpleserial_write('d', priv_key_d) - # Message to sign - ot.target.simpleserial_write('n', "Hello OTBN.".encode()) - - # Arm the scope - ot.scope.arm() - - # Ephemeral secret scalar k - if capture_cfg["key_len_bytes"] == 48: - secret_k = bytearray([ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - elif capture_cfg["key_len_bytes"] == 32: - secret_k = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF - ]) - else: - raise RuntimeError('secret_k must be either 32B or 48B') - # Send the ephemeral secret k and trigger the signature geneartion - ot.target.simpleserial_write('p', secret_k) - - # Wait until operation is done - ret = ot.scope.capture(poll_done=True) - # If getting inconsistent results (e.g. variable number of cycles), - # adding a sufficient sleep below here appears to fix things - time.sleep(1) - if ret: - raise RuntimeError('Timeout during capture') - # Check the number of cycles, where the trigger signal was high - cycles = ot.scope.adc.trig_count - print("Observed number of cycles: %d" % cycles) - - # Append the section into the waves array - waves = np.append(waves, ot.scope.get_last_trace(as_int=True)) + waves = capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, + secret_k, + priv_key_d, + msg) # Read 32 bytes of signature_r and signature_s back from the device sig_r = ot.target.simpleserial_read("r", @@ -1193,14 +1263,14 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): # Currently, we need to reprogram the firmware before every sign operation # TODO: Investigate the C code (ecc384_serial) to check if we can run multiple # signing operations without reloading the firmware. - reset_firmware = True + reset_firmware = False project = cw.create_project(capture_cfg["project_name"], overwrite=True) # Enable the streaming mode if ot.scope._is_husky: ot.scope.adc.stream_mode = True - ot.scope.adc.bits_per_sample = 8 + ot.scope.adc.bits_per_sample = 12 else: # TODO: Add cw-lite support raise RuntimeError('Only CW-Husky is supported now') @@ -1208,6 +1278,84 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): # Loop to collect traces for _ in tqdm(range(capture_cfg["num_traces"]), desc='Capturing', ncols=80): + # This part can be modified to create a new command. + # For example, a random secret scalar can be set using the following + # from numpy.random import default_rng + # rng = default_rng() + # secret_k0 = bytearray(rng.bytes(32)) + # secret_k1 = bytearray(rng.bytes(32)) + msg = "Hello OTBN.".encode() + # ECDSA-384 + if capture_cfg["key_len_bytes"] == 48: + # Set two shares of the private key d + priv_key_d0 = bytearray([ + 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, + 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, + 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA, + 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8, + 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, + 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 + ]) + priv_key_d1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # Set two shares of the scalar secret_k + secret_k0 = bytearray([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + secret_k1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # ECDSA-256 + elif capture_cfg["key_len_bytes"] == 32: + # Set two shares of the private key d + priv_key_d0 = bytearray([ + 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, + 0x02, 0x0c, 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, + 0x0c, 0xf0, 0x18, 0x0d, 0xf4, 0x6c, 0x0b, 0xda, + 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, 0x45, 0x55 + ]) + priv_key_d1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + # Set two shares of the scalar secret_k + secret_k0 = bytearray([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + secret_k1 = bytearray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]) + else: + raise RuntimeError('priv_key_d must be either 32B or 48B') + + # Combine the two shares of d and k + priv_key_d = priv_key_d0 + priv_key_d1 + secret_k = secret_k0 + secret_k1 + # Create an arrey to keep the traces waves = np.array([]) # Currently, we have to reload the firmware to be able to send a @@ -1216,53 +1364,20 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): if reset_firmware: ot.program_target(fw_bin, pll_frequency) - # Optional commands to overwrite the default values of the private key d, - # and the message msg - # The current values are set to the default values in the C code (ecc384_serial.c) - if capture_cfg["key_len_bytes"] == 48: - priv_key_d = bytearray([ - 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, 0x05, 0xB1, - 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, 0xE2, 0x3C, 0x3B, 0x66, - 0x7B, 0xF2, 0x97, 0xBA, 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, - 0x37, 0xD8, 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, - 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 - ]) - elif capture_cfg["key_len_bytes"] == 32: - priv_key_d = bytearray([ - 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, 0x02, 0x0c, - 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, 0x0c, 0xf0, 0x18, 0x0d, - 0xf4, 0x6c, 0x0b, 0xda, 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, - 0x45, 0x55 - ]) - else: - raise RuntimeError('priv_key_d must be either 32B or 48B') + # Optional commands to overwrite the default values declared in the C code. ot.target.simpleserial_write('d', priv_key_d) # Message to sign - ot.target.simpleserial_write('n', "Hello OTBN.".encode()) + ot.target.simpleserial_write('n', msg) + # Send the ephemeral secret k and trigger the signature geneartion + ot.target.simpleserial_write('k', secret_k) + + time.sleep(0.2) # Arm the scope ot.scope.arm() - # Ephemeral secret scalar k - if capture_cfg["key_len_bytes"] == 48: - secret_k = bytearray([ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - elif capture_cfg["key_len_bytes"] == 32: - secret_k = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF - ]) - else: - raise RuntimeError('secret_k must be either 32B or 48B') - # Send the ephemeral secret k and trigger the signature geneartion - ot.target.simpleserial_write('p', secret_k) + # Start the ECDSA operation + ot.target.simpleserial_write('p', bytearray([0x01])) # Wait until operation is done ret = ot.scope.capture(poll_done=True) diff --git a/cw/capture_ecdsa_cw310.yaml b/cw/capture_ecdsa_cw310.yaml index 60911bf0..2d9d8109 100644 --- a/cw/capture_ecdsa_cw310.yaml +++ b/cw/capture_ecdsa_cw310.yaml @@ -1,8 +1,13 @@ device: fpga_bitstream: objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit fw_bin: objs/ecc_serial_fpga_cw310.bin - # Target operating frequency - pll_frequency: 22000000 + # Target operating frequency: + # for ecdsa-simple: 25-50MHz (alignment issues above 66MHz) + # for ecdsa-stream: 15-20MHz (sampling_rate-adc_resolution tradeoff) + # More details on Husky stream mode can be found in the following links: + # https://github.com/lowRISC/ot-sca/issues/106#issuecomment-1359530023 + # https://rtfm.newae.com/Capture/ChipWhisperer-Husky/#streaming-mode + pll_frequency: 15000000 baudrate: 115200 capture: # Only ECDSA-256 (32) and ECDSA-384 (48) are supported at this moment. @@ -13,7 +18,8 @@ capture: num_samples: 262140 # Offset in samples offset: 0 - # scope gain in db - 13 for non-stream mode, 32.5 for stream mode + # scope gain in db - This may change for each setup, + # find a value for your setup scope_gain: 32.5 num_traces: 1 project_name: projects/opentitan_ecdsa_256 diff --git a/cw/objs/ecc384_serial_fpga_cw310.bin b/cw/objs/ecc384_serial_fpga_cw310.bin old mode 100644 new mode 100755 index 61a909b3..0f7cea31 Binary files a/cw/objs/ecc384_serial_fpga_cw310.bin and b/cw/objs/ecc384_serial_fpga_cw310.bin differ diff --git a/cw/objs/ecc_serial_fpga_cw310.bin b/cw/objs/ecc_serial_fpga_cw310.bin old mode 100644 new mode 100755 index b76090de..b049586e Binary files a/cw/objs/ecc_serial_fpga_cw310.bin and b/cw/objs/ecc_serial_fpga_cw310.bin differ diff --git a/cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit b/cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit old mode 100644 new mode 100755 index c284dab9..c07c6b98 Binary files a/cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit and b/cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit differ diff --git a/doc/img/ot-sca-cw310-clocking.png b/doc/img/ot-sca-cw310-clocking.png new file mode 100644 index 00000000..e5b488b2 --- /dev/null +++ b/doc/img/ot-sca-cw310-clocking.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e552a7da56963f24d0ed4a838dda1dc30b7cada61e938911ea463c8ef5893cf +size 89232