From 3f97ee4f30371f1f0788e7cd73c417d007c3a5a3 Mon Sep 17 00:00:00 2001 From: tmeissner Date: Tue, 8 Feb 2022 14:21:08 +0100 Subject: [PATCH] Add simple example verifying an aes unit --- .gitignore | 3 ++ env-setup.sh | 6 ++- requirements.txt | 1 + tests/Vai.py | 19 ++++++--- tests/tb_aes.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 .gitignore create mode 100644 tests/tb_aes.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1809249 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +cryptocores +libvhdl +cocotbext-wishbone diff --git a/env-setup.sh b/env-setup.sh index 6e00337..d1dab61 100755 --- a/env-setup.sh +++ b/env-setup.sh @@ -7,5 +7,9 @@ if [ ! -d cocotbext-wishbone/.git ]; then fi if [ ! -d libvhdl/.git ]; then - git clone https://github.com/tmeissner/libvhdl.git + git clone https://github.com/tmeissner/libvhdl.git +fi + +if [ ! -d cryptocores/.git ]; then + git clone https://github.com/tmeissner/cryptocores.git fi diff --git a/requirements.txt b/requirements.txt index ebee7d1..ff45dd3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ pyuvm # utilities wavedrom +pycryptodome diff --git a/tests/Vai.py b/tests/Vai.py index 20b71b4..d972391 100644 --- a/tests/Vai.py +++ b/tests/Vai.py @@ -8,7 +8,7 @@ class Vai: def __init__(self, clock, data, valid, accept, *args, **kwargs): self._version = "0.0.1" - self.log = logging.getLogger(f"cocotb.{data._path}") + self.log = logging.getLogger(f"cocotb.{valid._path}") self._data = data self._valid = valid @@ -28,17 +28,26 @@ class VaiDriver(Vai): self.log.info(" cocotbext-vai version %s", self._version) self.log.info(" Copyright (c) 2022 Torsten Meissner") - # Drive input defaults (setimmediatevalue to avoid x asserts) - self._data.setimmediatevalue(0) + # Hack to drive lists of signals + if isinstance(self._data, list): + for entry in self._data: + entry.setimmediatevalue(0) + else: + self._data.setimmediatevalue(0) self._valid.setimmediatevalue(0) async def send(self, data, sync=True): if sync: await self._clkedge - self.log.info("Sending data: %s", hex(data)) self._valid.value = 1 - self._data.value = data + # Hack to drive lists of signals + if isinstance(self._data, list): + for i in range(len(self._data)): + self._data[i].value = data[i] + else: + self.log.info("Sending data: %s", hex(data)) + self._data.value = data while True: await ReadOnly() diff --git a/tests/tb_aes.py b/tests/tb_aes.py new file mode 100644 index 0000000..8f1d3ab --- /dev/null +++ b/tests/tb_aes.py @@ -0,0 +1,105 @@ +import logging +import random +import cocotb +import pprint +from Vai import VaiDriver, VaiReceiver +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer, ReadOnly +from Crypto.Cipher import AES +from Crypto.Util.number import long_to_bytes, getRandomNBitInteger +import binascii + + +# Reset coroutine +async def reset_dut(reset_n, duration_ns): + reset_n.value = 0 + await Timer(duration_ns, units="ns") + reset_n.value = 1 + + +@cocotb.test() +async def test_aes_enc(dut): + """ Test AES encryption """ + + clkedge = RisingEdge(dut.clk_i) + + # Connect reset + reset = dut.reset_i + + # Instantiate VAI driver & receiver + _input = [dut.mode_i, dut.key_i, dut.data_i] + vai_driver = VaiDriver(dut.clk_i, _input, dut.valid_i, dut.accept_o) + vai_receiver = VaiReceiver(dut.clk_i, dut.data_o, dut.valid_o, dut.accept_i) + + # Drive input defaults (setimmediatevalue to avoid x asserts) + dut.mode_i.setimmediatevalue(0) + dut.key_i.setimmediatevalue(0) + dut.data_i.setimmediatevalue(0) + dut.valid_i.setimmediatevalue(0) + dut.accept_i.setimmediatevalue(0) + + clock = Clock(dut.clk_i, 10, units="ns") # Create a 10 ns period clock + cocotb.start_soon(clock.start()) # Start the clock + + # Execution will block until reset_dut has completed + dut._log.info("Hold reset") + await reset_dut(reset, 100) + dut._log.info("Released reset") + + # Test 10 AES calculations + for i in range(10): + await clkedge + _key = getRandomNBitInteger(128) + _data = getRandomNBitInteger(128) + # Drive AES inputs + await vai_driver.send([0, _key, _data]) + # Calc reference data + _aes = AES.new(long_to_bytes(_key), AES.MODE_ECB) + _ref = _aes.encrypt(long_to_bytes(_data)) + # Get DUT output data + _rec = await vai_receiver.receive() + assert _rec.buff == _ref, f"Encrypt error, got {_rec.buff}, expected {_ref}" + + +@cocotb.test() +async def test_aes_dec(dut): + """ Test AES decryption """ + + clkedge = RisingEdge(dut.clk_i) + + # Connect reset + reset = dut.reset_i + + # Instantiate VAI driver & receiver + _input = [dut.mode_i, dut.key_i, dut.data_i] + vai_driver = VaiDriver(dut.clk_i, _input, dut.valid_i, dut.accept_o) + vai_receiver = VaiReceiver(dut.clk_i, dut.data_o, dut.valid_o, dut.accept_i) + + # Drive input defaults (setimmediatevalue to avoid x asserts) + dut.mode_i.setimmediatevalue(0) + dut.key_i.setimmediatevalue(0) + dut.data_i.setimmediatevalue(0) + dut.valid_i.setimmediatevalue(0) + dut.accept_i.setimmediatevalue(0) + + clock = Clock(dut.clk_i, 10, units="ns") # Create a 10 ns period clock + cocotb.start_soon(clock.start()) # Start the clock + + # Execution will block until reset_dut has completed + dut._log.info("Hold reset") + await reset_dut(reset, 100) + dut._log.info("Released reset") + + # Test 10 AES calculations + for i in range(10): + await clkedge + _key = getRandomNBitInteger(128) + _data = getRandomNBitInteger(128) + # Drive AES inputs + await vai_driver.send([1, _key, _data]) + # Calc reference data + _aes = AES.new(long_to_bytes(_key), AES.MODE_ECB) + _ref = _aes.decrypt(long_to_bytes(_data)) + # Get DUT output data + _rec = await vai_receiver.receive() + assert _rec.buff == _ref, f"Decrypt error, got {_rec.buff}, expected {_ref}"