Running SOLN_LAB_3_3 with a Husky doesn't yield correct results

Hello vector,
We haven’t made the modification yet as we don’t have the part and the microsoldering tool, our soldering iron is way too big for this operation right now. I’ll come back to you when we have done it!

I have now compared my traces with the traces from the “simulated” lab and found that these do not show the significant negative drops I see in my traces. See below simulated traces on the left and the measurements from my Husky on the right:

Overall signal level seems to be lower as well, but that may be related to the reduced gain I applied in order to reduce the risk of running into errors (as @Shanly described above).
Other than the gain value, I use the standard startup and solution scripts. The CW reports VCCaux error at every startup, but it can be cleared and doesn’t return until the next restart.

Any suggestions what I can do to improve my setup?

I wouldn’t recommend trying to compare to the simulated labs, as they’re done with a completely different target (the STM32F3)

Thanks @Alex_Dewar, that makes sense. Is there a possibility that the VCCaux alarm has something to do with this behavior? I get the following reported when checking print(scope.errors) at startup

XADC errors  = VCCaux alarm, 
ADC errors   = False
extclk error = False
trace errors = False

Clearing with scope.XADC.status = 0 as defined in the docs seems to be successful.
Would anyone be able to share settings and a plot of traces of a successful run of Lab 3_3 with a v3 Husky?
I feel I have tried every possible setting and configuration in last six weeks and would like to make sure it is not a(nother) hardware issue.

The VCCaux alarm is sticky until you clear it. When does it happen? And what is the output of this when after it’s happened:

print(scope.XADC.get_vcc('vccaux', 'current'))
print(scope.XADC.get_vcc('vccaux', 'min'))
print(scope.XADC.get_vcc('vccaux', 'max'))

It’s not likely to be the cause for the issue you’re seeing, but it is curious.

What capacitor value did you use?

Try this notebook and report what you get for sad and std.
notebook.zip (1.9 KB)

Thanks @jpthibault. I really appreciate your support.
I am checking the scope.errors right before starting to capture the traces, check the current value of VCCaux and then reset the error. Running scope.XADC.get_vcc('vccaux') with a second argument (current, min, max) doesn’t work for some Python reason, reporting that the function receives three instead of one or two arguments. :person_shrugging:
Below my output:

XADC errors  = VCCaux alarm, 
ADC errors   = False
extclk error = False
trace errors = False

1.806884765625
Running scope.XADC.status = 0 ...
Done
XADC errors  = False
ADC errors   = False
extclk error = False
trace errors = False

1.808349609375

Looks stable from my perspective, min and max would be helpful for sure. I will try to find the issue here.

The capacitor I used is a 100pF X7R 50V from a trusted source and the improvement on the CPA lab was quite significant, while for Lab 3_3 it is not visible.

I executed the notebook (had to adjust some paths to match my installation) and received the following output:

std = 24.10216651470951, (0.06469655183900855 scaled)
0.006814599609375
sad = 25.33721142578123
std = 24.10216651470951

I would love to say that I was smart enough to understand these values and draw my conclusions… but I am not. What can you read from this?

You must be using an older release; use the develop branch.

That’s in line with what we’ve seen.
You should be able to succeed with the DPA attack. Could be a ghost peak problem; could be more traces are needed.

Thanks @jpthibault.
With all other potential issues out of the way, I finally solved it:
It was indeed a ghost peak problem. With my limited experience in power analysis, I wasn’t aware of the magnitude of ghost peaks. What I formerly though was the AES algorithm and lead to significant spikes in the plot turned out to be something completely different. The actual AES spikes where hiding somewhere in the noise (the actual peak is at sample 1900 rather than 1250 or 4300).

With the full_diffs_list plot in the Ghost Peaks chapter

fig = cw.plot()
for subkey in range(0, 16):
    fig *= cw.plot(full_diffs_list[subkey][known_key[subkey]])
fig

I finally received the following result:

zooming in on the now colorful peaks:

Setting the following parameters before sampling helped me to window the correct range:

scope.adc.offset = 1800
scope.adc.samples = 900

Big thanks to the NewAE team for the great support and patience.

1 Like

I have the Husky HWREV 1.1C, and need a lot more traces on Lab 3.3, as well as 4.2 compared to what’s mentioned in the notebook. Is adding the capacitor mentioned above a recommended solution?

Edit: When I change the ADC offset and samples as per above (to 1800 and 900 respectively), it seems Lab 4.2 actually works with only 50 traces. But I’m not sure why :slight_smile:

The capacitor improved the performance of Lab 4_2 significantly in my case. For Lab 3_3 I didn’t see any improvement.
The values for offset and no of samples, i.e. start and duration of analyzed section, in Lab 3_3 in the example above were chosen to select exactly the shown 16 peaks and filter out the much larger ghost peaks at 1300 and 4300.
I would assume that due to the very similar timing of the target firmware in Lab 3_3 and 4_2, the time window of leakage might also be similar.

1 Like

Thanks! Yes, that does make a lot of sense regarding the ADC parameters. I’ll consider making the HW changes then to see if there are any changes in the performance.

Hello,
Sorry for the delayed answer, we finally managed to perform the modification.
This happened when attempting to validate the hardware:

import chipwhisperer as cw
scope = cw.scope()

(ChipWhisperer Scope ERROR|File __init__.py:389) ChipWhisperer error state detected. Resetting and retrying connection...

---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\__init__.py:387, in scope(scope_type, name, sn, idProduct, bitstream, force, prog_speed, **kwargs)
    386 try:
--> 387     rtn.con(**kwargs)
    388 except IOError:

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\OpenADC.py:662, in OpenADC.con(self, sn, idProduct, bitstream, force, prog_speed, **kwargs)
    661 self.la_mmcm = XilinxMMCMDRP(self.la_drp)
--> 662 self.clock = ChipWhispererHuskyClock.ChipWhispererHuskyClock(self.sc, \
    663     self._fpga_clk, self.glitch_mmcm1, self.glitch_mmcm2)
    664 self.ADS4128 = ADS4128Settings(self.sc)

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:712, in ChipWhispererHuskyClock.__init__(self, oaiface, fpga_clk_settings, mmcm1, mmcm2)
    711 self.naeusb = oaiface.serial
--> 712 self.pll = CDCI6214(self.naeusb, mmcm1, mmcm2)
    713 self.fpga_clk_settings = fpga_clk_settings

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:36, in CDCI6214.__init__(self, naeusb, mmcm1, mmcm2)
     35 self._mmcm_vco_max = 1200e6
---> 36 self.setup()
     37 self.set_pll_input()

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:144, in CDCI6214.setup(self)
    143 # disable GPIO1/4 as inputs
--> 144 self.update_reg(0x00, (1 << 13) | (1 << 12), 0)
    146 self.update_reg(0x04, (1 << 3) | (1 << 4), 0) # turn off outputs 2 and 4

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:119, in CDCI6214.update_reg(self, addr, bits_to_set, bits_to_clear)
    118 # print(bits_to_set, bits_to_clear)
--> 119 reg_val = self.read_reg(addr, as_int=False)
    120 reg_val[0] &= 0xFF - bits_to_clear[0] # the not we want ;)

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:80, in CDCI6214.read_reg(self, addr, as_int)
     79 if data[0] != 2:
---> 80     raise IOError("PLL/I2C Error, got {}".format(data))
     82 if as_int is True:

OSError: PLL/I2C Error, got bytearray(b'\x01\x08\x00')

During handling of the above exception, another exception occurred:

OSError                                   Traceback (most recent call last)
Cell In[3], line 2
      1 import chipwhisperer as cw
----> 2 scope = cw.scope()

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\__init__.py:393, in scope(scope_type, name, sn, idProduct, bitstream, force, prog_speed, **kwargs)
    391     time.sleep(2)
    392     rtn = scope_type()
--> 393     rtn.con(**kwargs)
    394 return rtn

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\OpenADC.py:662, in OpenADC.con(self, sn, idProduct, bitstream, force, prog_speed, **kwargs)
    660 self.glitch_mmcm2 = XilinxMMCMDRP(self.glitch_drp2)
    661 self.la_mmcm = XilinxMMCMDRP(self.la_drp)
--> 662 self.clock = ChipWhispererHuskyClock.ChipWhispererHuskyClock(self.sc, \
    663     self._fpga_clk, self.glitch_mmcm1, self.glitch_mmcm2)
    664 self.ADS4128 = ADS4128Settings(self.sc)
    665 self.XADC = XADCSettings(self.sc)

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:712, in ChipWhispererHuskyClock.__init__(self, oaiface, fpga_clk_settings, mmcm1, mmcm2)
    710 self.oa = oaiface
    711 self.naeusb = oaiface.serial
--> 712 self.pll = CDCI6214(self.naeusb, mmcm1, mmcm2)
    713 self.fpga_clk_settings = fpga_clk_settings
    714 self.fpga_clk_settings.freq_ctr_src = "extclk"

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:36, in CDCI6214.__init__(self, naeusb, mmcm1, mmcm2)
     34 self._mmcm_vco_min = 600e6
     35 self._mmcm_vco_max = 1200e6
---> 36 self.setup()
     37 self.set_pll_input()
     38 self.set_outdiv(3, 0)

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:144, in CDCI6214.setup(self)
    131 """Do required initial setup.
    132 
    133 Does the following:
   (...)
    141  * Use register to select PLL input instead of pin
    142 """
    143 # disable GPIO1/4 as inputs
--> 144 self.update_reg(0x00, (1 << 13) | (1 << 12), 0)
    146 self.update_reg(0x04, (1 << 3) | (1 << 4), 0) # turn off outputs 2 and 4
    148 self.update_reg(0x05, 0, 0b11111110111) # turn on power to everything

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:119, in CDCI6214.update_reg(self, addr, bits_to_set, bits_to_clear)
    116     bits_to_clear = tmp
    118 # print(bits_to_set, bits_to_clear)
--> 119 reg_val = self.read_reg(addr, as_int=False)
    120 reg_val[0] &= 0xFF - bits_to_clear[0] # the not we want ;)
    121 reg_val[1] &= 0xFF - bits_to_clear[1]

File c:\users\\chipwhisperer5_64\cw\home\portable\chipwhisperer\software\chipwhisperer\capture\scopes\cwhardware\ChipWhispererHuskyClock.py:80, in CDCI6214.read_reg(self, addr, as_int)
     77 data = self.naeusb.readCtrl(0x29, dlen=3)
     79 if data[0] != 2:
---> 80     raise IOError("PLL/I2C Error, got {}".format(data))
     82 if as_int is True:
     83     return (data[1]) | (data[2] << 8)

OSError: PLL/I2C Error, got bytearray(b'\x01\x08\x00')

The Husky was working fine before. Do you know why this is happening ? This is the part we used for our modification: https://www.mouser.se/ProductDetail/KEMET/C0402C101K5TACAUTO?qs=P%2FxahI%252BVehm4DIVfs7vRXA%3D%3D

If that can help, husky is alive and status led is blinking correctly.

Thank you so much for your support,
Shanly

That’s not a good sign: it means we’re not able to read properly from the PLL chip (U10). It’s close to C49, which suggests it may have been damaged. Here we should be reading [2, 0, 0], and you’re getting [1, 8, 0] instead.

The I2C lines which handle PLL communication are near the top right corner, on the backside, if you’re up to inspecting for damage and checking with a logic analyzer.

Hello,
We have done a optical inspection of the soldering, it seems to look fine ? Here are some picture for reference




We have tried reinstalling the drivers in the hopes of succeeding a firmware update but reinstalling the drivers did not change the issues so the CW is unavailable for any kind of firmware update.

Thank you for your suggestion. This kind of hardware debugging is really out of our competence set as it is, could you eventually please provide us with further guidance ? Is there any further output we can provide you with ?

Email sales@newae.com with a reference to this C49 modification and we’ll take the next steps from there.

Thank you for your swift support! The performances of the Husky have significantly improved.
Running the solution lab actually brings us to a output close to @vector247

The peaks are now clearly visible (solution peaks)


So, based on the precedent graph, I know that subkey 0 has a peak of around 0.4 at around 1900, which means it is the dark blue one. It stands particularly well at 2500 too.

With a brute windowing of [2500:]

Subkey  0 - most likely 0C (actual 2B)
 Top 5 guesses: 
   0C - Diff = 0.002146
   9F - Diff = 0.001743
   CD - Diff = 0.001732
   0B - Diff = 0.001723
   26 - Diff = 0.001691


Subkey  1 - most likely 7E (actual 7E)
 Top 5 guesses: 
   7E - Diff = 0.003172
   6F - Diff = 0.001874
   3F - Diff = 0.001803
   19 - Diff = 0.001760
   1F - Diff = 0.001724


Subkey  2 - most likely 15 (actual 15)
 Top 5 guesses: 
   15 - Diff = 0.002919
   B5 - Diff = 0.001939
   DC - Diff = 0.001771
   E6 - Diff = 0.001708
   9A - Diff = 0.001681


Subkey  3 - most likely 16 (actual 16)
 Top 5 guesses: 
   16 - Diff = 0.003997
   AB - Diff = 0.002369
   7D - Diff = 0.002168
   8F - Diff = 0.002138
   12 - Diff = 0.002023


Subkey  4 - most likely 17 (actual 28)
 Top 5 guesses: 
   17 - Diff = 0.001870
   8A - Diff = 0.001764
   C8 - Diff = 0.001743
   39 - Diff = 0.001697
   20 - Diff = 0.001676


Subkey  5 - most likely AE (actual AE)
 Top 5 guesses: 
   AE - Diff = 0.002839
   BF - Diff = 0.001852
   B9 - Diff = 0.001778
   4B - Diff = 0.001716
   3A - Diff = 0.001693


Subkey  6 - most likely D2 (actual D2)
 Top 5 guesses: 
   D2 - Diff = 0.002999
   B9 - Diff = 0.001864
   BB - Diff = 0.001808
   7C - Diff = 0.001801
   91 - Diff = 0.001796


Subkey  7 - most likely A6 (actual A6)
 Top 5 guesses: 
   A6 - Diff = 0.003777
   4A - Diff = 0.002487
   1B - Diff = 0.002405
   CD - Diff = 0.002318
   34 - Diff = 0.002312


Subkey  8 - most likely CC (actual AB)
 Top 5 guesses: 
   CC - Diff = 0.002222
   E0 - Diff = 0.001935
   F3 - Diff = 0.001681
   02 - Diff = 0.001678
   EA - Diff = 0.001630


Subkey  9 - most likely F7 (actual F7)
 Top 5 guesses: 
   F7 - Diff = 0.003574
   7F - Diff = 0.002292
   B5 - Diff = 0.001947
   9C - Diff = 0.001926
   06 - Diff = 0.001876


Subkey 10 - most likely 15 (actual 15)
 Top 5 guesses: 
   15 - Diff = 0.003001
   FB - Diff = 0.002578
   35 - Diff = 0.002027
   AF - Diff = 0.001811
   52 - Diff = 0.001772


Subkey 11 - most likely 88 (actual 88)
 Top 5 guesses: 
   88 - Diff = 0.003423
   35 - Diff = 0.002113
   E3 - Diff = 0.002094
   E5 - Diff = 0.001994
   7D - Diff = 0.001992


Subkey 12 - most likely 57 (actual 09)
 Top 5 guesses: 
   57 - Diff = 0.001821
   F4 - Diff = 0.001712
   B1 - Diff = 0.001660
   40 - Diff = 0.001632
   DF - Diff = 0.001630


Subkey 13 - most likely CF (actual CF)
 Top 5 guesses: 
   CF - Diff = 0.003567
   A6 - Diff = 0.001885
   72 - Diff = 0.001840
   22 - Diff = 0.001680
   A4 - Diff = 0.001647


Subkey 14 - most likely 4F (actual 4F)
 Top 5 guesses: 
   4F - Diff = 0.003053
   FC - Diff = 0.001882
   27 - Diff = 0.001869
   CF - Diff = 0.001854
   2D - Diff = 0.001831


Subkey 15 - most likely 3C (actual 3C)
 Top 5 guesses: 
   3C - Diff = 0.003877
   81 - Diff = 0.002414
   57 - Diff = 0.002140
   C2 - Diff = 0.001997
   C9 - Diff = 0.001954

We recovered almost all bytes! Except 0, 4, 8, and 12 (The +4 offset between each is intriguing aha). In those cases, the real key doesn’t make it to the top 5.

Windowing still remains quite difficult and we don’t get a perfect solution. I tried to optimize it with something like [(offset_start + cycle*subkey) : (offset_end + cycle*subkey)] and I cannot seem to find such parameters that give me something perfect. Do you have any suggestion on how to solve this?

On the other hand, Solution Lab for 4.2 worked perfectly so the main issue have been resolved on my side. A huge thanks to @Alex_Dewar, @jpthibault and other members of the NewAE team. Thanks also to the community for contributing to this topic and helping us get to the bottom of this issue!