I corrected the issue, but the trigger is still not being detected, and I receive the following error message:
ChipWhisperer Scope WARNING|File _OpenADCInterface.py:732) Timeout in OpenADC capture(), no trigger seen! Trigger forced, data is invalid. Status: 0b
I was able to successfully perform the glitch attack on the AES circuit provided by ChipWhisperer for the CW305 board. I configured the trigger pin (tio_trigger
) in Vivado to activate whenever my circuit begins its operation, as done in the example. However, the trigger is still not being detected.
Here is the full script for the attack:
import time
import numpy as np
from chipwhisperer.common.traces import Trace
import chipwhisperer as cw
from tqdm import trange
import random
import string
FPGA_ID='100t'
def reboot_flush():
scope.io.nrst = False
time.sleep(0.05)
scope.io.nrst = "high_z"
time.sleep(0.05)
target.flush()
scope = cw.scope()
scope.gain.db = 25
scope.adc.samples = 129
scope.adc.offset = 0
scope.adc.basic_mode = "rising_edge"
scope.clock.clkgen_freq = 20E6
scope.clock.adc_src = "clkgen_x4"
scope.trigger.triggers = "tio4"
scope.io.tio1 = "serial_rx"
scope.io.tio2 = "serial_tx"
scope.io.hs2 = "clkgen"
# program target:
bitpath = r"C:\Users\julia\Desktop\Vivado_Projects\Fault_Injection\clock_glitch_target_V4\clock_glitch_target_V4.runs\impl_1\cw305_top_gl.bit"
target = cw.target(scope, cw.targets.CW305, fpga_id=FPGA_ID, force=True, bsfile=bitpath)
target.vccint_set(1.0)
# we only need PLL1:
target.pll.pll_enable_set(False)
target.pll.pll_outenable_set(False, 0)
target.pll.pll_outenable_set(False, 1)
target.pll.pll_outenable_set(False, 2)
# run at 20 MHz:
target.pll.pll_outfreq_set(20E6, 1)
# 1ms is plenty of idling time
target.clkusbautooff = False
target.clksleeptime = 1
# ensure ADC is locked:
scope.clock.reset_adc()
assert (scope.clock.adc_locked), "ADC failed to lock"
target.usb_clk_setenabled(1)
scope.glitch.clk_src = "clkgen" # set glitch input clock
scope.glitch.output = "clock_xor" # glitch_out = clk ^ glitch
scope.glitch.trigger_src = "ext_single" # glitch only after scope.arm() called
scope.glitch.width = 10
scope.io.hs2 = "glitch" # output glitch_out on the clock line
scope.io.glitch_lp = False
scope.glitch.ext_offset = 300 # started at 2
scope.glitch.repeat = 2 # started at 2
scope.adc.timeout = 0.1
import struct
import numpy as np
from tqdm import trange
# Experiment parameters
glitch_values = [
(1.0, 0.5),
(1.0, 1.0),
(2.0, 5.0),
(3.0, 8.0),
]
rounds_per_point = 5
glitch_outputs = []
print("Running selected glitches")
expected_result_1= 14
expected_result_2= 7
for w, off in glitch_values:
# Configure the current glitch
scope.glitch.width = w
scope.glitch.ext_offset = off
# (w,off)
result = {"width": w, "offset": off, "resets": 0, "successes": []}
glitch_outputs.append(result)
for _ in range(rounds_per_point):
# Si el scope quedó disparado, reiniciamos
if scope.adc.state:
result["resets"] += 1
reboot_flush()
# Armamos el scope para esperar el trigger en TIO4
scope.arm()
# Cargamos entradas
a = 2
b = 1
data = (b << 4) | a
target.fpga_write(0x00, [data])
# Disparamos el circuito
target.fpga_write(0x01, [0x01]) # activar start
# Capturamos la traza y el glitch
ret = scope.capture()
# Leemos resultados
# Leer resultado de multiplicación (9 bits)
result1_low = target.fpga_read(0x02, 1)[0] # bits [7:0]
result1_high = target.fpga_read(0x03, 1)[0] & 0x01 # bit [8]
result_1 = (result1_high << 8) | result1_low
# Leer resultado de suma (5 bits)
result_2 = target.fpga_read(0x04, 1)[0] & 0x1F
if ret: # timeout → no llegó trigger
result["resets"] += 1
reboot_flush()
else:
# Comparamos la suma con el valor esperado
if result_1 != expected_result_1:
result["successes"].append(result_1)
print(f"Successful glitch: sum={result_1}, setting=(w={w}, off={off})")
if result_2 != expected_result_2:
result["successes"].append(result_2)
print(f"Successful glitch: sum={result_2}, setting=(w={w}, off={off})")