What accounts for the difference in output between the two CW-Husky devices?

Hello,
I have recently developed an interest in the CW-Husky and have begun conducting research on it. However, there are still many aspects I do not fully understand.

I currently have two CW-Husky devices, which I will refer to as Husky A and Husky B for clarity.
When capturing the same code and location using both devices, I observed noticeable differences in the resulting waveforms. This led me to three key questions.

I am trying to understand whether one of the devices is faulty, whether both are behaving correctly, or, if both are functioning properly, what causes the discrepancy between their outputs.

The first and second images were captured using Husky A, while the third and fourth images were captured using Husky B.




I can think of 3 possibilities:

  1. Is it the same physical target? Even if they’re both e.g. SAM4S targets, they could come from different batches. Also check the target board version on the PCB.
  2. One of your Huskies is a later revision with the C49 capacitor mounted.
  3. If you’re using an external clock and an older chipwhisperer release, there were a few sampling clock phase issues (e.g. Husky: frequency-dependent ADC sampling clock phase when using external clock · Issue #501 · newaetech/chipwhisperer · GitHub) that have since been resolved. Upgrade to the 6.0 release, or an up-to-date develop branch, to get those fixes.
1 Like

Thank you for your response.
Based on your answer, I have the following three questions:

  1. I would like both Huskies to produce the same waveform. If everything else is the same — the code, the position, the board, and the chip (CW-308, STM32F303) — but only the Husky is different, what actions should be taken?

  2. Between Husky A and Husky B, which one should be adjusted? And what kind of result can we expect from that adjustment?

  3. I’d like to know whether only one of Husky A or B falls within the normal range, or if both are within the acceptable range. Also, if both waveforms are considered normal, which one aligns better with current trends?

Before I can answer that, please tell me:

  1. What does “position” refer to?
  2. Post a picture of your setup.
  3. On the back of Husky there is a sticker that shows the hardware revision (“HWREV”); what is it?
  4. What is the output of:
import chipwhisperer as cw
print("cw.__version__")
  1. With the setup that you used to obtain the power traces that you show above, what is the output of print(scope)?
1 Like
  1. The term “position” refers to the section where the power trace was captured. For example, as shown in the attached images, a trigger was inserted into the source code, and based on this trigger, the same section was captured using both Husky A and Husky B.




In other words, I wanted to point out that although it is the same section, the capture results differ depending on whether Husky A or Husky B is used. The code used to capture the attached images is as follows:

[Trigger Insertion Code]
for (i = 0; i < size; i++) {
    output[i] = exp(input[i]);
    sum += output[i];
    trigger_high();
    trigger_low();
}

[Waveform Capture Code]
SCOPETYPE = 'OPENADC'
PLATFORM = 'CW308_STM32F3'
CRYPTO_TARGET = 'NONE’

import struct
import numpy as np
import matplotlib.pyplot as plt
from tqdm.notebook import tqdm
from tensorflow.keras.datasets import mnist
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
import os

output_notebook()

%%bash -s "$PLATFORM" "$CRYPTO _TARGET"
cd ../../hardware/victims/firmware/outputlayer
make PLATFORM=CW308_STM32F3 CRYPTO_TARGET=NONE

%run "../../jupyter/Setup_Scripts/Setup_Generic.ipynb"
fw_path = "../../hardware/victims/firmware/outputlayer/simpleserial-cifar-{}.hex".format(PLATFORM)
cw.program_target(scope, prog, fw_path)

def reboot_flush():
    reset_target(scope)
    target.flush()

(_, _), (x_test, y_test) = mnist.load_data()
x_test = x_test / 255.0
Label = y_test.reshape(-1)
soft_mlp_mid_values = np.load('pre_softmax_MLP.npy')

scope.gain.db = 10
scope.adc.samples = 650
scope.adc.presamples = 500
scope.trigger.module = 'basic’

reboot_flush()
target.simpleserial_write('g', soft_mlp_mid_values[0])
_ = target.simpleserial_read('z', 0)
scope.arm()
target.simpleserial_write('m', b'')
trace = cw.capture_trace(scope, target, None, None)
_ = target.simpleserial_read('r', 10 * 4)

wave = trace.wave
p = figure(title="Trigger Trace (Live)", plot_width=1000, plot_height=300)
p.line(range(len(wave)), wave)
show(p)

ref_path = "HuskyTest/Husky_A_trace.npy" # or "HuskyTest/Husky_B_trace.npy"

detail = -56
maxSample = 64 + detail
ref_start = scope.adc.presamples + detail
ref_end = scope.adc.presamples + maxSample

force_save = False
if force_save or not os.path.exists(ref_path):
    ref_trace = trace.wave[ref_start : ref_end]
    
    os.makedirs(os.path.dirname(ref_path), exist_ok=True)
    np.save(ref_path, ref_trace)
    print(f"[âś“] Save new ref_trace : {ref_path}")
else:
    print(f"[i] Use existing ref_trace ({ref_path})")

ref_trace = np.load(ref_path)

plt.figure(figsize=(10, 3))
plt.plot(ref_trace)
plt.title("Reference Trace")
plt.xlabel("Sample Index")
plt.ylabel("Amplitude")
plt.grid(True)
plt.tight_layout()
plt.show()
  1. Attached are images of the setup with the CW-Husky, CW-308, and STM32F303. For the waveform comparison, only the Husky was swapped during capture.

  1. The HWREV values are as follows:
    Husky A = 1.1C
    Husky B = 1.1D

  2. The following is the result of print(cw.__version__):
    Husky A = 5.6.1
    Husky B = 5.6.1

  3. The following is the result of print(scope).

Husky A

cwhusky Device
sn             = 50203220325531583230353235323034
fpga_buildtime = 11/3/2022, 22:46
fw_version = 
    major = 1
    minor = 4
    debug = 0
gain = 
    mode = low
    gain = 54
    db   = 9.770642201834864
adc = 
    state                    = False
    basic_mode               = rising_edge
    timeout                  = 2
    offset                   = 0
    presamples               = 500
    samples                  = 650
    decimate                 = 1
    trig_count               = 560
    stream_mode              = False
    test_mode                = False
    bits_per_sample          = 12
    segments                 = 1
    segment_cycles           = 0
    segment_cycle_counter_en = False
    clip_errors_disabled     = False
    lo_gain_errors_disabled  = False
    errors                   = False
clock = 
    clkgen_src             = system
    clkgen_freq            = 7370129.87012987
    adc_mul                = 4
    adc_freq               = 29480519.48051948
    freq_ctr               = 0
    clkgen_locked          = True
    adc_phase              = 0
    extclk_monitor_enabled = False
    extclk_error           = False
    extclk_tolerance       = 102.996826171875
trigger = 
    module   = basic
    triggers = tio4
io = 
    tio1            = serial_rx
    tio2            = serial_tx
    tio3            = high_z
    tio4            = high_z
    pdid            = high_z
    pdic            = high_z
    nrst            = high_z
    glitch_hp       = False
    glitch_lp       = False
    extclk_src      = hs1
    hs2             = clkgen
    target_pwr      = True
    tio_states      = (1, 1, 1, 0)
    cdc_settings    = bytearray(b'\x00\x00\x00\x00')
    aux_io_mcx      = high_z
    glitch_trig_mcx = trigger
glitch = 
    enabled           = False
    mmcm_locked       = False
    num_glitches      = 1
    clk_src           = target
    width             = 0
    offset            = 0
    trigger_src       = manual
    arm_timing        = after_scope
    ext_offset        = 0
    repeat            = 1
    output            = clock_xor
    phase_shift_steps = 4592
ADS4128 = 
    mode      = normal
    low_speed = True
    hi_perf   = 2
LA = 
    present                  = True
    enabled                  = False
    clkgen_enabled           = False
    locked                   = False
    clk_source               = pll
    trigger_source           = glitch
    oversampling_factor      = 1
    sampling_clock_frequency = 0.0
    downsample               = 1
    capture_group            = glitch
    capture_depth            = 0
trace = 
    present      = True
    enabled      = False
    errors       = False
    trace_synced = False
    trace_mode   = parallel
    trace_width  = 4
    clock = 
        fe_clock_alive   = True
        fe_clock_src     = target_clock
        clkgen_enabled   = False
        fe_freq          = 7370258.331298828
        swo_clock_locked = False
        swo_clock_freq   = 0.0
    capture = 
        trigger_source         = firmware trigger
        use_husky_arm          = False
        raw                    = True
        rules_enabled          = []
        rules                  = []
        mode                   = while_trig
        count                  = 0
        max_triggers           = 1
        triggers_generated     = 1
        record_syncs           = False
        matched_pattern_data   = 0000000000000000
        matched_pattern_counts = [0, 0, 0, 0, 0, 0, 0, 0]
XADC = 
    status                               = good
    current temperature [C]              = 41.6
    maximum temperature [C]              = 43.3
    user temperature alarm trigger [C]   = 80.0
    user temperature reset trigger [C]   = 59.9
    device temperature alarm trigger [C] = 89.9
    device temperature reset trigger [C] = 59.9
    vccint                               = 1.006
    vccaux                               = 1.793
    vccbram                              = 1.004
userio = 
    mode       = normal
    direction  = 0
    drive_data = 0
    status     = 511
LEDs = 
    setting = 0 (default, as labelled)
errors = 
    XADC errors  = False
    ADC errors   = False
    extclk error = False
    trace errors = False

Husky B

cwhusky Device
sn             = 502032204c5846303030313139313039
fpga_buildtime = 11/3/2022, 22:46
fw_version = 
    major = 1
    minor = 4
    debug = 0
gain = 
    mode = low
    gain = 54
    db   = 9.770642201834864
adc = 
    state                    = False
    basic_mode               = rising_edge
    timeout                  = 2
    offset                   = 0
    presamples               = 500
    samples                  = 650
    decimate                 = 1
    trig_count               = 560
    stream_mode              = False
    test_mode                = False
    bits_per_sample          = 12
    segments                 = 1
    segment_cycles           = 0
    segment_cycle_counter_en = False
    clip_errors_disabled     = False
    lo_gain_errors_disabled  = False
    errors                   = False
clock = 
    clkgen_src             = system
    clkgen_freq            = 7370129.87012987
    adc_mul                = 4
    adc_freq               = 29480519.48051948
    freq_ctr               = 0
    clkgen_locked          = True
    adc_phase              = 0
    extclk_monitor_enabled = False
    extclk_error           = False
    extclk_tolerance       = 102.996826171875
trigger = 
    module   = basic
    triggers = tio4
io = 
    tio1            = serial_rx
    tio2            = serial_tx
    tio3            = high_z
    tio4            = high_z
    pdid            = high_z
    pdic            = high_z
    nrst            = high_z
    glitch_hp       = False
    glitch_lp       = False
    extclk_src      = hs1
    hs2             = clkgen
    target_pwr      = True
    tio_states      = (1, 1, 1, 0)
    cdc_settings    = bytearray(b'\x00\x00\x00\x00')
    aux_io_mcx      = high_z
    glitch_trig_mcx = trigger
glitch = 
    enabled           = False
    mmcm_locked       = False
    num_glitches      = 1
    clk_src           = target
    width             = 0
    offset            = 0
    trigger_src       = manual
    arm_timing        = after_scope
    ext_offset        = 0
    repeat            = 1
    output            = clock_xor
    phase_shift_steps = 4592
ADS4128 = 
    mode      = normal
    low_speed = True
    hi_perf   = 2
LA = 
    present                  = True
    enabled                  = False
    clkgen_enabled           = False
    locked                   = False
    clk_source               = pll
    trigger_source           = glitch
    oversampling_factor      = 1
    sampling_clock_frequency = 0.0
    downsample               = 1
    capture_group            = glitch
    capture_depth            = 0
trace = 
    present      = True
    enabled      = False
    errors       = False
    trace_synced = False
    trace_mode   = parallel
    trace_width  = 4
    clock = 
        fe_clock_alive   = True
        fe_clock_src     = target_clock
        clkgen_enabled   = False
        fe_freq          = 7370246.887207031
        swo_clock_locked = False
        swo_clock_freq   = 0.0
    capture = 
        trigger_source         = firmware trigger
        use_husky_arm          = False
        raw                    = True
        rules_enabled          = []
        rules                  = []
        mode                   = while_trig
        count                  = 0
        max_triggers           = 1
        triggers_generated     = 1
        record_syncs           = False
        matched_pattern_data   = 0000000000000000
        matched_pattern_counts = [0, 0, 0, 0, 0, 0, 0, 0]
XADC = 
    status                               = good
    current temperature [C]              = 48.0
    maximum temperature [C]              = 49.3
    user temperature alarm trigger [C]   = 80.0
    user temperature reset trigger [C]   = 59.9
    device temperature alarm trigger [C] = 89.9
    device temperature reset trigger [C] = 59.9
    vccint                               = 1.002
    vccaux                               = 1.805
    vccbram                              = 1.002
userio = 
    mode       = normal
    direction  = 0
    drive_data = 0
    status     = 511
LEDs = 
    setting = 0 (default, as labelled)
errors = 
    XADC errors  = False
    ADC errors   = False
    extclk error = False
    trace errors = False

Thank you for answering my questions.

You are using version 5.6.1 of the ChipWhisperer software, which is very old; please consider upgrading to the latest 6.0.0 release.

However the power trace differences you are seeing are not caused by the out-of-date release. As I noted earlier, your 1.1D unit has an extra capacitor mounted in its analog front-end, which changes its frequency response.

You can choose to add C49 to your 1.1C Husky or remove it from your 1.1D Husky, but as noted in the link above, this is done at your own risk and voids the warranty.

If you require your two Huskies to be identical, email sales@newae.com, with a reference to this forum post, and we will discuss your options.

1 Like