diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 49e1de5..edeadd0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -25,8 +25,19 @@ jobs: - name: Build targets shell: nix develop .#ci -c bash -e {0} run: | - make - make RNG=NISTKAT nistkat + make_platform() { + echo "::group::make platform $1" + make PLATFORM="$1" + echo "::endgroup::" + + echo "::group::make platform $1 nistkat" + make PLATFORM="$1" RNG=NISTKAT nistkat + echo "::endgroup::" + } + + make_platform stm32f4discovery + make_platform nucleo-f767zi + - name: Build for emulation on QEMU shell: nix develop .#ci -c bash -e {0} run: | @@ -38,7 +49,7 @@ jobs: id: func_test shell: nix develop .#ci -c bash -e {0} run: | - tests func -e -v stm32f4discovery + tests func -v mps2-an386 - name: Speed test id: speed_test shell: nix develop .#ci -c bash -e {0} @@ -46,7 +57,7 @@ jobs: success() || steps.func_test.conclusion == 'failure' run: | - tests speed -e -v stm32f4discovery + tests speed -v mps2-an386 - name: Stack test id: stack_test shell: nix develop .#ci -c bash -e {0} @@ -55,7 +66,7 @@ jobs: || steps.func_test.conclusion == 'failure' || steps.speed_test.conclusion == 'failure' run: | - tests stack -e -v stm32f4discovery + tests stack -v mps2-an386 - name: Nistkat test shell: nix develop .#ci -c bash -e {0} if: | @@ -64,4 +75,4 @@ jobs: || steps.speed_test.conclusion == 'failure' || steps.stack_test.conclusion == 'failure' run: | - tests nistkat -e -v stm32f4discovery + tests nistkat -v mps2-an386 diff --git a/flake.nix b/flake.nix index ca50eca..9776601 100644 --- a/flake.nix +++ b/flake.nix @@ -19,34 +19,39 @@ perSystem = { pkgs, ... }: let libopencm3 = pkgs.callPackage ./libopencm3.nix { - targets = [ "stm32/f4" ]; + targets = [ "stm32/f4" "stm32/f7" ]; }; - core = with pkgs; [ - # formatter & linters - nixpkgs-fmt - shfmt - astyle # 3.4.10 + core = builtins.attrValues { + libopencm3 = libopencm3; - # build dependencies - gcc-arm-embedded-13 # arm-gnu-toolchain-13.2.rel1 - python311 - qemu # 8.1.5 - libopencm3 + inherit (pkgs) + # formatter & linters + nixpkgs-fmt + shfmt + astyle# 3.4.10 - yq - python311Packages.pyserial # 3.5 - python311Packages.click - ]; + # build dependencies + gcc-arm-embedded-13# arm-gnu-toolchain-13.2.rel1 + python311 + qemu# 8.1.5 + + yq; + + inherit (pkgs.python311Packages) + pyserial# 3.5 + click; + }; in { - devShells.default = with pkgs; mkShellNoCC { - packages = core ++ [ - direnv - nix-direnv + devShells.default = pkgs.mkShellNoCC { + packages = core ++ builtins.attrValues { + inherit (pkgs) + direnv + nix-direnv - # debug dependencies - openocd # 0.12.0 - ]; + # debug dependencies + openocd; # 0.12.0 + }; shellHook = '' export OPENCM3_DIR=${libopencm3} @@ -55,7 +60,7 @@ ''; }; - devShells.ci = with pkgs; mkShellNoCC { + devShells.ci = pkgs.mkShellNoCC { packages = core; shellHook = '' diff --git a/hal/devices.data b/hal/devices.data index 7a648eb..b051f2f 100644 --- a/hal/devices.data +++ b/hal/devices.data @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 stm32f407vg stm32f4 ROM=1024K RAM=128K stm32f4 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 CPU=cortex-m4 FPU=hard-fpv4-sp-d16 +stm32f767zi stm32f7 ROM=2048K RAM=384K +stm32f7 END ROM_OFF=0x08000000 RAM_OFF=0x20010000 CPU=cortex-m7 FPU=hard-fpv5-sp-d16 diff --git a/hal/hal-opencm3.c b/hal/hal-opencm3.c index 20b2d49..c784c8b 100644 --- a/hal/hal-opencm3.c +++ b/hal/hal-opencm3.c @@ -7,13 +7,12 @@ #include #include #include - -#if defined(STM32F407VG) - #include #include #include #include + +#if defined(STM32F407VG) #include #define SERIAL_GPIO GPIOA #define SERIAL_USART USART2 @@ -39,64 +38,14 @@ const struct rcc_clock_scale benchmarkclock = { .apb2_frequency = 24000000, }; -#elif defined(STM32L476RG) -#include -#include -#include -#include +#elif defined(STM32F767ZI) #include +#include -#define SERIAL_GPIO GPIOA -#define SERIAL_USART USART2 -#define SERIAL_PINS (GPIO2 | GPIO3) +#define SERIAL_GPIO GPIOD +#define SERIAL_USART USART3 +#define SERIAL_PINS (GPIO8 | GPIO9) #define STM32 -#define NUCLEO_BOARD -#elif defined(STM32F303RCT7) -#include -#include -#include -#include - -#define SERIAL_GPIO GPIOA -#define SERIAL_USART USART1 -#define SERIAL_PINS (GPIO9 | GPIO10) -#define STM32 -#define CW_BOARD -#elif defined(STM32F415RGT6) -#include -#include -#include -#include -#include - -#define SERIAL_GPIO GPIOA -#define SERIAL_USART USART1 -#define SERIAL_PINS (GPIO9 | GPIO10) -#define STM32 -#define CW_BOARD -#elif defined(STM32L4R5ZI) -#include -#include -#include -#include -#include -#include - -#define SERIAL_GPIO GPIOG -#define SERIAL_USART LPUART1 -#define SERIAL_PINS (GPIO8 | GPIO7) -#define NUCLEO_L4R5_BOARD - -/* Patched function for newer PLL not yet supported by opencm3 */ -void _rcc_set_main_pll(uint32_t source, uint32_t pllm, uint32_t plln, uint32_t pllp, - uint32_t pllq, uint32_t pllr) { - RCC_PLLCFGR = (RCC_PLLCFGR_PLLM(pllm) << RCC_PLLCFGR_PLLM_SHIFT) | - (plln << RCC_PLLCFGR_PLLN_SHIFT) | - ((pllp & 0x1Fu) << 27u) | /* NEWER PLLP */ - (source << RCC_PLLCFGR_PLLSRC_SHIFT) | - (pllq << RCC_PLLCFGR_PLLQ_SHIFT) | - (pllr << RCC_PLLCFGR_PLLR_SHIFT) | RCC_PLLCFGR_PLLREN; -} #else #error Unsupported libopencm3 board @@ -126,200 +75,42 @@ static void clock_setup(enum clock_mode clock) { } rcc_periph_clock_enable(RCC_RNG); - rng_enable(); flash_prefetch_enable(); - #elif defined(CW_BOARD) - (void) clock; - /* Some STM32 Platform */ - rcc_periph_clock_enable(RCC_GPIOH); - rcc_osc_off(RCC_HSE); - rcc_osc_bypass_enable(RCC_HSE); - rcc_osc_on(RCC_HSE); - rcc_wait_for_osc_ready(RCC_HSE); - - rcc_ahb_frequency = 7372800; - rcc_apb1_frequency = 7372800; - rcc_apb2_frequency = 7372800; - _clock_freq = 7372800; - rcc_set_hpre(RCC_CFGR_HPRE_DIV_NONE); - # if defined(STM32F3) - rcc_set_ppre1(RCC_CFGR_PPRE1_DIV_NONE); - rcc_set_ppre2(RCC_CFGR_PPRE2_DIV_NONE); - # elif defined(STM32F4) - rcc_set_ppre1(RCC_CFGR_PPRE_DIV_NONE); - rcc_set_ppre2(RCC_CFGR_PPRE_DIV_NONE); - # if defined(STM32F415RGT6) - flash_set_ws(FLASH_ACR_LATENCY_0WS); - rcc_set_sysclk_source(RCC_CFGR_SW_HSE); - rcc_wait_for_sysclk_status(RCC_HSE); - - /* HSI and PLL needed for RNG - that's why we can't use rcc_clock_setup_pll()*/ - rcc_osc_on(RCC_HSI); - rcc_wait_for_osc_ready(RCC_HSI); - rcc_osc_off(RCC_PLL); - rcc_set_main_pll_hse(12, 196, 4, 7, 0); - - rcc_osc_on(RCC_PLL); - rcc_wait_for_osc_ready(RCC_PLL); - - rcc_periph_clock_enable(RCC_RNG); - rng_enable(); - # endif - # endif - rcc_set_sysclk_source(RCC_CFGR_SW_HSE); - rcc_wait_for_sysclk_status(RCC_HSE); - #elif defined(NUCLEO_BOARD) - /* NUCLEO-L476RG Board */ + #elif defined(STM32F7) switch (clock) { case CLOCK_BENCHMARK: - /* Benchmark straight from the HSI16 without prescaling */ - rcc_osc_on(RCC_HSI16); - rcc_wait_for_osc_ready(RCC_HSI16); - rcc_ahb_frequency = 16000000; - rcc_apb1_frequency = 16000000; - rcc_apb2_frequency = 16000000; - _clock_freq = 16000000; - rcc_set_hpre(RCC_CFGR_HPRE_NODIV); - rcc_set_ppre1(RCC_CFGR_PPRE_NODIV); - rcc_set_ppre2(RCC_CFGR_PPRE_NODIV); - flash_dcache_enable(); - flash_icache_enable(); - flash_set_ws(FLASH_ACR_LATENCY_0WS); - flash_prefetch_enable(); - rcc_set_sysclk_source(RCC_CFGR_SW_HSI16); - rcc_wait_for_sysclk_status(RCC_HSI16); + rcc_clock_setup_hsi(&rcc_3v3[RCC_CLOCK_3V3_24MHZ]); break; case CLOCK_FAST: default: - rcc_osc_on(RCC_HSI16); - rcc_wait_for_osc_ready(RCC_HSI16); - rcc_ahb_frequency = 80000000; - rcc_apb1_frequency = 80000000; - rcc_apb2_frequency = 80000000; - _clock_freq = 80000000; - rcc_set_hpre(RCC_CFGR_HPRE_NODIV); - rcc_set_ppre1(RCC_CFGR_PPRE_NODIV); - rcc_set_ppre2(RCC_CFGR_PPRE_NODIV); - rcc_osc_off(RCC_PLL); - while (rcc_is_osc_ready(RCC_PLL)); - /* Configure the PLL oscillator (use CUBEMX tool -> scale HSI16 to 80MHz). */ - rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_HSI16, 1, 10, RCC_PLLCFGR_PLLP_DIV7, RCC_PLLCFGR_PLLQ_DIV2, RCC_PLLCFGR_PLLR_DIV2); - /* Enable PLL oscillator and wait for it to stabilize. */ - rcc_osc_on(RCC_PLL); - rcc_wait_for_osc_ready(RCC_PLL); - flash_dcache_enable(); - flash_icache_enable(); - flash_set_ws(FLASH_ACR_LATENCY_4WS); - flash_prefetch_enable(); - rcc_set_sysclk_source(RCC_CFGR_SW_PLL); - rcc_wait_for_sysclk_status(RCC_PLL); + rcc_clock_setup_hsi(&rcc_3v3[RCC_CLOCK_3V3_216MHZ]); break; } rcc_periph_clock_enable(RCC_RNG); - rng_enable(); - #elif defined(NUCLEO_L4R5_BOARD) - rcc_periph_clock_enable(RCC_PWR); - rcc_periph_clock_enable(RCC_SYSCFG); - pwr_set_vos_scale(PWR_SCALE1); - /* The L4R5ZI chip also needs the R1MODE bit in PWR_CR5 register set, but - OpenCM3 doesn't support this yet. But luckily the default value for the bit - is 1. */ - switch (clock) { - case CLOCK_BENCHMARK: - /* Benchmark straight from the HSI16 without prescaling */ - rcc_osc_on(RCC_HSI16); - rcc_wait_for_osc_ready(RCC_HSI16); - rcc_ahb_frequency = 20000000; - rcc_apb1_frequency = 20000000; - rcc_apb2_frequency = 20000000; - _clock_freq = 20000000; - rcc_set_hpre(RCC_CFGR_HPRE_NODIV); - rcc_set_ppre1(RCC_CFGR_PPRE_NODIV); - rcc_set_ppre2(RCC_CFGR_PPRE_NODIV); - rcc_osc_off(RCC_PLL); - while (rcc_is_osc_ready(RCC_PLL)); - /* Configure the PLL oscillator (use CUBEMX tool -> scale HSI16 to 20MHz). */ - _rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_HSI16, 1, 10, 2, RCC_PLLCFGR_PLLQ_DIV2, RCC_PLLCFGR_PLLR_DIV8); - /* Enable PLL oscillator and wait for it to stabilize. */ - rcc_osc_on(RCC_PLL); - flash_dcache_enable(); - flash_icache_enable(); - flash_set_ws(FLASH_ACR_LATENCY_0WS); - flash_prefetch_enable(); - rcc_set_sysclk_source(RCC_CFGR_SW_PLL); - rcc_wait_for_sysclk_status(RCC_PLL); - break; - case CLOCK_FAST: - default: - rcc_osc_on(RCC_HSI16); - rcc_wait_for_osc_ready(RCC_HSI16); - rcc_ahb_frequency = 120000000; - rcc_apb1_frequency = 120000000; - rcc_apb2_frequency = 120000000; - _clock_freq = 120000000; - rcc_set_hpre(RCC_CFGR_HPRE_NODIV); - rcc_set_ppre1(RCC_CFGR_PPRE_NODIV); - rcc_set_ppre2(RCC_CFGR_PPRE_NODIV); - rcc_osc_off(RCC_PLL); - while (rcc_is_osc_ready(RCC_PLL)); - /* Configure the PLL oscillator (use CUBEMX tool -> scale HSI16 to 120MHz). */ - _rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_HSI16, 1, 15, 2, RCC_PLLCFGR_PLLQ_DIV2, RCC_PLLCFGR_PLLR_DIV2); - /* Enable PLL oscillator and wait for it to stabilize. */ - rcc_osc_on(RCC_PLL); - rcc_wait_for_osc_ready(RCC_PLL); - flash_dcache_enable(); - flash_icache_enable(); - flash_set_ws(0x05); - flash_prefetch_enable(); - rcc_set_sysclk_source(RCC_CFGR_SW_PLL); - rcc_wait_for_sysclk_status(RCC_PLL); - break; - } - rcc_osc_on(RCC_HSI48); /* HSI48 must always be on for RNG */ - rcc_wait_for_osc_ready(RCC_HSI48); - rcc_periph_clock_enable(RCC_RNG); - rcc_set_clock48_source(RCC_CCIPR_CLK48SEL_HSI48); - rng_enable(); + flash_art_enable(); + flash_prefetch_enable(); #else #error Unsupported platform #endif } void usart_setup() { - #if defined(DISCOVERY_BOARD) + #if defined(STM32F7) + rcc_periph_clock_enable(RCC_GPIOD); + rcc_periph_clock_enable(RCC_USART3); + #elif defined(DISCOVERY_BOARD) rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_USART2); - #elif defined(CW_BOARD) - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_USART1); #elif defined(NUCLEO_BOARD) rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_USART2); - #elif defined(NUCLEO_L4R5_BOARD) - rcc_periph_clock_enable(RCC_GPIOG); - rcc_periph_clock_enable(RCC_LPUART1); - - PWR_CR2 |= PWR_CR2_IOSV; - gpio_set_output_options(SERIAL_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, SERIAL_PINS); - gpio_set_af(SERIAL_GPIO, GPIO_AF8, SERIAL_PINS); - gpio_mode_setup(SERIAL_GPIO, GPIO_MODE_AF, GPIO_PUPD_NONE, SERIAL_PINS); - usart_set_baudrate(SERIAL_USART, SERIAL_BAUD); - usart_set_databits(SERIAL_USART, 8); - usart_set_stopbits(SERIAL_USART, USART_STOPBITS_1); - usart_set_mode(SERIAL_USART, USART_MODE_TX_RX); - usart_set_parity(SERIAL_USART, USART_PARITY_NONE); - usart_set_flow_control(SERIAL_USART, USART_FLOWCONTROL_NONE); - usart_disable_rx_interrupt(SERIAL_USART); - usart_disable_tx_interrupt(SERIAL_USART); - usart_enable(SERIAL_USART); #else #error Unsupported platform #endif - #if defined(DISCOVERY_BOARD) || defined(NUCLEO_BOARD) || defined(CW_BOARD) + #if defined(DISCOVERY_BOARD) || defined(NUCLEO_BOARD) || defined(STM32F7) gpio_set_output_options(SERIAL_GPIO, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, SERIAL_PINS); gpio_set_af(SERIAL_GPIO, GPIO_AF7, SERIAL_PINS); gpio_mode_setup(SERIAL_GPIO, GPIO_MODE_AF, GPIO_PUPD_PULLUP, SERIAL_PINS); @@ -347,6 +138,7 @@ void hal_setup(const enum clock_mode clock) { clock_setup(clock); usart_setup(); systick_setup(); + rng_enable(); // wait for the first systick overflow // improves reliability of the benchmarking scripts since it makes it much diff --git a/libopencm3.nix b/libopencm3.nix index 3e0d4bc..7df4c77 100644 --- a/libopencm3.nix +++ b/libopencm3.nix @@ -26,7 +26,7 @@ stdenvNoCC.mkDerivation rec { ''; dontConfigure = true; buildPhase = '' - make ${if targets == [] then "lib" else "TARGETS=${lib.concatStrings targets}"} + make ${if targets == [] then "lib" else "TARGETS='${lib.concatMapStrings (t: t + " ") targets}'"} ''; installPhase = '' runHook preInstall @@ -43,7 +43,7 @@ stdenvNoCC.mkDerivation rec { dontStrip = true; noAuditTmpdir = true; - meta = with lib; { + meta = { description = "Open source ARM Cortex-M microcontroller library"; homepage = "https://libopencm3.org/"; }; diff --git a/mk/nucleo-f767zi.mk b/mk/nucleo-f767zi.mk new file mode 100644 index 0000000..23fc3e6 --- /dev/null +++ b/mk/nucleo-f767zi.mk @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +DEVICE=stm32f767zi +OPENCM3_TARGET=lib/stm32/f7 +override DEVICES_DATA := hal/devices.data + +include mk/opencm3.mk diff --git a/scripts/tests b/scripts/tests index 4b6a717..a7f3cd9 100755 --- a/scripts/tests +++ b/scripts/tests @@ -10,6 +10,9 @@ import subprocess import click import logging import sys +import re +from enum import Enum +from types import SimpleNamespace from functools import reduce # utilities for interacting with the board @@ -20,9 +23,12 @@ def serial_ports(): if platform.system() == "Windows": ports = ["COM%s" % (i + 1) for i in range(256)] elif platform.system() == "Darwin": - ports = glob.glob("/dev/tty.usbserial*") + ports = glob.glob("/dev/tty.usb*") + + r = re.compile(".*tty.usb(serial-|modem)[0-9]+$") + ports = [p for p in ports if r.match(p)] elif platform.system() == "Linux": - ports = glob.glob("/dev/ttyUSB*") + ports = glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") else: raise PlatformError("Unsupported platform") @@ -39,10 +45,10 @@ def usbdev(): return dev -async def flash(cfg, bin): +async def flash(cfg, bin, verbose): subprocess.run( ["openocd", "-f", cfg, "-c", f"program {bin} verify reset exit"], - stdout=subprocess.DEVNULL, + stdout=subprocess.DEVNULL if not verbose else None, stderr=subprocess.STDOUT, ) @@ -55,9 +61,9 @@ async def read(dev): return x[1:-1] -async def flush_and_read(dev, cfg, bin): +async def flash_and_read(dev, cfg, bin, verbose): # assume the first result is the usb device to use - asyncio.create_task(flash(cfg, bin)) + asyncio.create_task(flash(cfg, bin, verbose)) read_task = asyncio.create_task(read(dev)) result = await read_task logging.debug(str(result, encoding="utf-8")) @@ -78,9 +84,70 @@ def count(bstr, match): return str(bstr, encoding="utf8").count(match) +# constants + + +class RNG(Enum): + HAL = 1 + NOTRAND = 2 + NISTKAT = 3 + + def __str__(self): + return self.name + + +class TEST_TYPE(Enum): + TEST = 1 # functional test + SPEED = 2 + STACK = 3 + NISTKAT = 4 + + def __str__(self): + return self.name.lower() + + +class PLATFORM(Enum): + STM32F4DISCOVERY = 1 + MPS2_AN386 = 2 + NUCLEO_F767ZI = 3 + + def __str__(self): + return self.name.lower().replace("_", "-") + + +class RecursiveNamespace(SimpleNamespace): + + @staticmethod + def map_entry(entry): + if isinstance(entry, dict): + return RecursiveNamespace(**entry) + + return entry + + def __init__(self, **kwargs): + super().__init__(**kwargs) + for key, val in kwargs.items(): + if type(val) == dict: + setattr(self, key, RecursiveNamespace(**val)) + elif type(val) == list: + setattr(self, key, list(map(self.map_entry, val))) + + +platform_map = RecursiveNamespace( + **{ + f"{PLATFORM.STM32F4DISCOVERY}": { + "openocd_cfg": "board/stm32f4discovery.cfg", + }, + f"{PLATFORM. NUCLEO_F767ZI}": { + "openocd_cfg": "board/st_nucleo_f7.cfg", + }, + f"{PLATFORM.MPS2_AN386}": {}, + } +) + + def base_test( test_type, - emulate, platform, ntests, expect_proc, @@ -94,18 +161,31 @@ def base_test( """ config_logger(verbose) - if emulate: - platform = getattr(platform_map, platform).qemu_platform - else: + if not hasattr(platform_map, platform): + logging.error("unsupported platform {platform}") + sys.exit(1) + + platform_cfg = None + if hasattr(getattr(platform_map, platform), "openocd_cfg"): platform_cfg = getattr(platform_map, platform).openocd_cfg + if test_type == TEST_TYPE.NISTKAT: + rng = RNG.NISTKAT + elif ( + platform_cfg is not None + ): # if platform_cfg is provided, then it is not running on qemu + rng = RNG.HAL + else: + rng = RNG.NOTRAND + p = subprocess.run( - ["make", f"NTESTS={ntests}", f"PLATFORM={platform}"] - + [f"emulate {test_type}"] * emulate - + [f"{test_type}"] * (not emulate) - + ["RNG=NISTKAT"] * (test_type == "nistkat") - + ["RNG=NOTRND"] * (emulate and test_type != "nistkat") - + ["RNG=HAL"] * (not emulate and test_type != "nistkat"), + [ + "make", + f"PLATFORM={platform}", + f"NTESTS={ntests}", + f"{test_type}", + f"RNG={rng}", + ], stdout=subprocess.DEVNULL if not verbose else None, ) logging.info(format(subprocess.list2cmdline(p.args))) @@ -119,21 +199,31 @@ def base_test( else: logging.info(f"Check {file} passed") - if not emulate: + if platform_cfg is not None: dev = usbdev() for scheme in ["mlkem512", "mlkem768", "mlkem1024"]: file = f"elf/{scheme}-{test_type}.elf" expect = expect_proc(scheme) - if emulate: + if platform_cfg is None: actual = actual_proc( subprocess.run( - ["make", "emulate run", f"ELF_FILE={file}", f"PLATFORM={platform}"], + [ + "qemu-system-arm", + "-machine", + f"{platform}", + "-nographic", + "-semihosting", + "-kernel", + f"{file}", + ], capture_output=True, ).stdout ) else: - actual = actual_proc(asyncio.run(flush_and_read(dev, platform_cfg, file))) + actual = actual_proc( + asyncio.run(flash_and_read(dev, platform_cfg, file, verbose)) + ) check(file, expect, actual) @@ -150,23 +240,11 @@ _shared_options = [ type=bool, help="Show verbose output or not", ), - click.option( - "-e", - "--emulate", - is_flag=True, - show_default=True, - default=False, - type=bool, - help="Emulate on the QEMU or not", - ), -] - -_shared_args = [ click.argument( "platform", nargs=1, - type=click.Choice(["stm32f4discovery"]), - ) + type=click.Choice([f"{p}" for p in PLATFORM]), + ), ] @@ -174,47 +252,10 @@ def add_options(options): return lambda func: reduce(lambda f, o: o(f), reversed(options), func) -def add_args(args): - return lambda func: reduce(lambda f, o: o(f), reversed(args), func) - - -# commands -from types import SimpleNamespace - - -class RecursiveNamespace(SimpleNamespace): - - @staticmethod - def map_entry(entry): - if isinstance(entry, dict): - return RecursiveNamespace(**entry) - - return entry - - def __init__(self, **kwargs): - super().__init__(**kwargs) - for key, val in kwargs.items(): - if type(val) == dict: - setattr(self, key, RecursiveNamespace(**val)) - elif type(val) == list: - setattr(self, key, list(map(self.map_entry, val))) - - -platform_map = RecursiveNamespace( - **{ - "stm32f4discovery": { - "qemu_platform": "mps2-an386", - "openocd_cfg": "board/stm32f4discovery.cfg", - } - } -) - - @click.command( short_help="Run for the specified platform and hex file without parsing the output", context_settings={"show_default": True}, ) -@add_args(_shared_args) @add_options(_shared_options) @click.option( "-b", @@ -222,13 +263,15 @@ platform_map = RecursiveNamespace( type=click.Path(), help="The binary hex file that you wanted to test.", ) -def run(platform, bin, verbose, emulate): +def run(platform, bin, verbose): config_logger(True) dev = usbdev() try: result = asyncio.run( - flush_and_read(dev, getattr(platform_map, platform).openocd_cfg, bin) + flash_and_read( + dev, getattr(platform_map, platform).openocd_cfg, bin, verbose + ) ) logging.info(result) except asyncio.CancelledError: @@ -238,14 +281,12 @@ def run(platform, bin, verbose, emulate): @click.command( short_help="Run functional tests", context_settings={"show_default": True} ) -@add_args(_shared_args) @add_options(_shared_options) @click.option("-i", "--iterations", default=1, type=int, help="Number of tests") -def func(platform, iterations, verbose, emulate): +def func(platform, iterations, verbose): try: base_test( - "test", - emulate, + TEST_TYPE.TEST, platform, iterations, lambda _: iterations * 3, @@ -258,16 +299,14 @@ def func(platform, iterations, verbose, emulate): @click.command(short_help="Run speed tests", context_settings={"show_default": True}) @add_options(_shared_options) -@add_options(_shared_args) @click.option("-i", "--iterations", default=1, type=int, help="Number of tests") -def speed(platform, iterations, verbose, emulate): +def speed(platform, iterations, verbose): try: base_test( - "speed", - emulate, + TEST_TYPE.SPEED, platform, iterations, - lambda _: iterations, + lambda _: 1, lambda output: count(output, "OK"), verbose, ) @@ -277,12 +316,10 @@ def speed(platform, iterations, verbose, emulate): @click.command(short_help="Run stack tests", context_settings={"show_default": True}) @add_options(_shared_options) -@add_options(_shared_args) -def stack(platform, verbose, emulate): +def stack(platform, verbose): try: base_test( - "stack", - emulate, + TEST_TYPE.STACK, platform, 0, lambda _: 1, @@ -295,8 +332,7 @@ def stack(platform, verbose, emulate): @click.command(short_help="Run nistkat tests", context_settings={"show_default": True}) @add_options(_shared_options) -@add_options(_shared_args) -def nistkat(platform, verbose, emulate): +def nistkat(platform, verbose): def scheme_hash(scheme): result = subprocess.run( [ @@ -316,8 +352,7 @@ def nistkat(platform, verbose, emulate): try: base_test( - "nistkat", - emulate, + TEST_TYPE.NISTKAT, platform, 0, scheme_hash, diff --git a/test/speed.c b/test/speed.c index 9191ae2..fac91c5 100644 --- a/test/speed.c +++ b/test/speed.c @@ -2,17 +2,24 @@ #include "hal.h" #include "kem.h" #include "sendfn.h" +#include "randombytes.h" #include #include #define printcycles(S, U) send_unsignedll((S), (U)) +static int cmp_uint64_t(const void *a, const void *b) { + return (int)((*((const uint64_t *)a)) - (*((const uint64_t *)b))); +} + int main(void) { unsigned char key_a[CRYPTO_BYTES], key_b[CRYPTO_BYTES]; unsigned char sk[CRYPTO_SECRETKEYBYTES]; unsigned char pk[CRYPTO_PUBLICKEYBYTES]; unsigned char ct[CRYPTO_CIPHERTEXTBYTES]; + unsigned char kg_rand[2 * CRYPTO_BYTES], enc_rand[CRYPTO_BYTES]; + uint64_t cycles_kg[NTESTS], cycles_enc[NTESTS], cycles_dec[NTESTS]; unsigned long long t0, t1; int i; @@ -20,32 +27,47 @@ int main(void) { SERIAL_MARKER(); + randombytes(kg_rand, 2 * CRYPTO_BYTES); + randombytes(enc_rand, CRYPTO_BYTES); + for (i = 0; i < NTESTS; i++) { // Key-pair generation t0 = hal_get_time(); - crypto_kem_keypair(pk, sk); + crypto_kem_keypair_derand(pk, sk, kg_rand); t1 = hal_get_time(); - printcycles("keypair cycles:", t1 - t0); + cycles_kg[i] = t1 - t0; + } + for (i = 0; i < NTESTS; i++) { // Encapsulation t0 = hal_get_time(); - crypto_kem_enc(ct, key_a, pk); + crypto_kem_enc_derand(ct, key_a, pk, enc_rand); t1 = hal_get_time(); - printcycles("encaps cycles:", t1 - t0); + cycles_enc[i] = t1 - t0; + } + for (i = 0; i < NTESTS; i++) { // Decapsulation t0 = hal_get_time(); crypto_kem_dec(key_b, ct, sk); t1 = hal_get_time(); - printcycles("decaps cycles:", t1 - t0); - - if (memcmp(key_a, key_b, CRYPTO_BYTES)) { - hal_send_str("ERROR KEYS\n"); - } else { - hal_send_str("OK KEYS\n"); - } - hal_send_str("+"); + cycles_dec[i] = t1 - t0; + } + + if (memcmp(key_a, key_b, CRYPTO_BYTES)) { + hal_send_str("ERROR KEYS\n"); + } else { + hal_send_str("OK KEYS\n"); } + hal_send_str("+"); + + qsort(cycles_kg, NTESTS, sizeof(uint64_t), cmp_uint64_t); + qsort(cycles_enc, NTESTS, sizeof(uint64_t), cmp_uint64_t); + qsort(cycles_dec, NTESTS, sizeof(uint64_t), cmp_uint64_t); + + printcycles("keypair cycles", cycles_kg[NTESTS >> 1]); + printcycles("encaps cycles", cycles_enc[NTESTS >> 1]); + printcycles("decaps cycles", cycles_dec[NTESTS >> 1]); SERIAL_MARKER();