How to capture more samples than the hardware supports?

How to capture more samples than the hardware supports?#

Each ChipWhisperer capture hardware has a maximum number of samples that it can capture. What to do if your target operation is longer?

With CW-Pro and CW-Husky, you have the option of streaming (see “How to use streaming mode?”, which has its own limitation (the maximum sampling rate is reduced).

With CW-Husky, you also have the option of using segmented capture (see “How to use segmented capture?”).

Here we show that one way to work around the sample limitation is to capture the target operation in several steps, using scope.adc.offset to grab of different “chunk” each time.

Supported Capture Hardware:
❌ CW-Nano
✅ CW-Lite
✅ CW-Pro
✅ CW-Husky

Required ChipWhisperer software installation:
✅ any release

%run '../connect.ipynb'

If your target is running simpleserial-aes firmware, this will run the target AES operation. For different target firmware, substitute with what’s needed to make your target “go”:

trace = cw.capture_trace(scope, target, bytearray(16), bytearray(16))

We can find the operation length with scope.adc.trig_count (as explained in “How long is the target operation?”):

oplen = scope.adc.trig_count
print('Operation length: %d cycles' % oplen)
Operation length: 31864 cycles

Let’s say we want to also capture the UART communication that happens after, so we try extend the capture to grab an additional 200000 samples.

Depending on your capture hardware, this will throw an error:

try:
    scope.adc.samples = oplen + 200000
    trace = cw.capture_trace(scope, target, bytearray(16), bytearray(16))
    if scope._is_husky:
        assert not scope.adc.errors, scope.adc.errors
except Exception as e:
    print('ERROR: cannot do it! %s' % e)
    if scope._is_husky:
        scope.errors.clear()
ERROR: cannot do it! slow FIFO underflow, fast FIFO overflow, 

What we can do instead is capture the maximum possible number of samples (call this N); then repeat the same operation and capture the next N samples by setting scope.adc.offset = N, and so on until all the samples have been gathered.

To be useful, this technique requires that the target can be made to repeat the exact same operation.

import math
from tqdm.notebook import tnrange
import numpy as np
total_samples = oplen + 400000
scope.adc.samples = 24400
segments = math.ceil(total_samples / scope.adc.samples)
scope.adc.offset = 0
composite_wave = np.array([])
for j in tnrange(segments, desc='Capturing trace segments'):
    trace = cw.capture_trace(scope, target, bytearray(16), bytearray(16))
    composite_wave = np.append(composite_wave, trace.wave)
    scope.adc.offset += scope.adc.samples

We can now see the target operation, followed by the UART activity section, followed by the target’s idle state:

cw.plot(composite_wave)