Falcon: ARM DSP (SMLA*/SMUAD) accelerated verify NTT + norm

Add an optional Cortex-M (ARMv7E-M / ARMv8-M) DSP-accelerated verify path,
auto-enabled on cores with the DSP extension (__ARM_FEATURE_DSP; Cortex-M4/M7/
M33). It is bit-identical to the scalar Barrett path (validated over 40k random
polynomials per level) and controlled by WOLFSSL_FALCON_NTT_DSP /
WOLFSSL_FALCON_NO_NTT_DSP.

  - NTT/iNTT butterflies process two packed 16-bit coefficients per iteration:
    SMLABB/SMLATB 16x16 twiddle multiplies (values are < q < 2^14), SADD16/
    SSUB16 packed adds, and a USUB16+SEL packed conditional subtract of q.
  - The pointwise multiply packs two coefficients per iteration (SMLABB/SMLATT).
  - The squared l2-norm accumulates two coefficients per SMUAD (a.lo^2+a.hi^2).

Tested on the STM32H563 (Cortex-M33) emulator m33mu via the new
IDE/m33mu-falcon-verify harness: the DSP path accepts a genuine Falcon-512 KAT
signature and rejects a tampered one (BKPT 0x7f), with SMUAD/USUB16/SEL/SMLABB
confirmed present in the image.

Also fixes three latent verify-only (WOLFSSL_FALCON_VERIFY_ONLY) build issues
surfaced by the embedded target:
  - falcon.h: include random.h unconditionally so WC_RNG is visible for the
    always-declared wc_falcon_sign_msg prototype.
  - falcon.c: define falcon_store_pub_behind_priv unconditionally
    (wc_falcon_import_public, a verify-only op, calls it).
  - falcon.c: silence unused inLen/rng in the verify-only sign stub.
pull/10827/head
Daniele Lacamera 2026-07-01 09:13:32 +02:00
parent debc59f70b
commit 0fa4e0d160
13 changed files with 812 additions and 9 deletions

View File

@ -0,0 +1,5 @@
build/
app-falcon.elf
app-falcon.bin
app-falcon.sym
app-falcon.dis

View File

@ -0,0 +1,58 @@
CC := arm-none-eabi-gcc
OBJCOPY ?= arm-none-eabi-objcopy
NM ?= arm-none-eabi-nm
OBJDUMP ?= arm-none-eabi-objdump
CFLAGS := -mcpu=cortex-m33 -mthumb -Os -ffreestanding
CFLAGS += -fdata-sections -ffunction-sections -g -ggdb -Wall -Wextra -Werror
CFLAGS += -I. -I../.. -DWOLFSSL_USER_SETTINGS
CFLAGS_WOLFSSL := $(CFLAGS)
CFLAGS_WOLFSSL := $(filter-out -Werror,$(CFLAGS_WOLFSSL))
CFLAGS_WOLFSSL += -Wno-unused-function -Wno-unused-variable
LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections
APP_SRCS := main.c ivt.c syscalls.c
# Native Falcon verify path: public wrapper + core (NTT/hash-to-point/codec) +
# SHAKE256, plus the minimal runtime (memory, wc_port).
WOLFSSL_SRCS := \
../../wolfcrypt/src/falcon.c \
../../wolfcrypt/src/wc_falcon.c \
../../wolfcrypt/src/sha3.c \
../../wolfcrypt/src/sha256.c \
../../wolfcrypt/src/hash.c \
../../wolfcrypt/src/memory.c \
../../wolfcrypt/src/wc_port.c \
../../wolfcrypt/src/wolfmath.c
APP_OBJS := $(patsubst %.c,build/%.o,$(APP_SRCS))
WOLFSSL_OBJS := $(patsubst ../../%.c,build/%.o,$(WOLFSSL_SRCS))
OBJS := $(APP_OBJS) $(WOLFSSL_OBJS)
all: app-falcon.bin
app-falcon.elf: $(OBJS) target.ld
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) \
-Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group -o $@
app-falcon.bin: app-falcon.elf
$(OBJCOPY) -O binary $< $@
build/%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
build/wolfcrypt/src/%.o: ../../wolfcrypt/src/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS_WOLFSSL) -c $< -o $@
symbols: app-falcon.elf
$(NM) -n app-falcon.elf > app-falcon.sym
$(OBJDUMP) -d app-falcon.elf > app-falcon.dis
clean:
rm -rf build app-falcon.elf app-falcon.bin app-falcon.sym app-falcon.dis
.PHONY: all symbols clean

View File

@ -0,0 +1,38 @@
# m33mu-falcon-verify
Minimal STM32H563 (Cortex-M33) bare-metal firmware that drives wolfCrypt's
native **Falcon-512 verify** path under `m33mu`, exercising the ARM DSP
acceleration (SMLAxx / SMUAD + packed-halfword SADD16/SSUB16/USUB16/SEL) that
auto-enables on cores with the DSP extension (`__ARM_FEATURE_DSP`).
The firmware imports the Falcon-512 KAT public key, verifies a genuine
signature (must be accepted) and a one-byte-tampered signature (must be
rejected). The NTT / iNTT / pointwise multiply / squared-norm all run through
the DSP path (`WOLFSSL_FALCON_NTT_DSP`, bit-identical to the scalar Barrett
path).
BKPT markers:
- `0x7f`: valid accepted **and** tampered rejected (success)
- `0x7c`: valid signature was rejected
- `0x7d`: tampered signature was accepted
- `0x71`: verify returned an operational error
- `0x70`: setup/init failure
Build (needs `arm-none-eabi-gcc` on PATH):
```sh
make -C IDE/m33mu-falcon-verify
```
Run:
```sh
m33mu --cpu stm32h563 --expect-bkpt 0x7f IDE/m33mu-falcon-verify/app-falcon.bin
```
Confirm the DSP instructions were actually compiled in:
```sh
make -C IDE/m33mu-falcon-verify symbols
grep -E '\b(smuad|smlabb|usub16|sel)\b' IDE/m33mu-falcon-verify/app-falcon.dis
```
`kat.h` holds the Falcon-512 KAT vectors (public key + signature) extracted from
`wolfcrypt/test/test.c`.

View File

@ -0,0 +1,42 @@
#include <stdint.h>
extern void Reset_Handler(void);
extern unsigned long _estack;
static void default_handler(void)
{
__asm volatile("bkpt #0x7b");
while (1) {
}
}
void NMI_Handler(void) __attribute__((weak, alias("default_handler")));
void HardFault_Handler(void) __attribute__((weak, alias("default_handler")));
void MemManage_Handler(void) __attribute__((weak, alias("default_handler")));
void BusFault_Handler(void) __attribute__((weak, alias("default_handler")));
void UsageFault_Handler(void) __attribute__((weak, alias("default_handler")));
void SVC_Handler(void) __attribute__((weak, alias("default_handler")));
void DebugMon_Handler(void) __attribute__((weak, alias("default_handler")));
void PendSV_Handler(void) __attribute__((weak, alias("default_handler")));
void SysTick_Handler(void) __attribute__((weak, alias("default_handler")));
__attribute__((section(".isr_vector")))
const uint32_t vector_table[16 + 64] = {
[0] = (uint32_t)&_estack,
[1] = (uint32_t)&Reset_Handler,
[2] = (uint32_t)&NMI_Handler,
[3] = (uint32_t)&HardFault_Handler,
[4] = (uint32_t)&MemManage_Handler,
[5] = (uint32_t)&BusFault_Handler,
[6] = (uint32_t)&UsageFault_Handler,
[7] = 0,
[8] = 0,
[9] = 0,
[10] = 0,
[11] = (uint32_t)&SVC_Handler,
[12] = (uint32_t)&DebugMon_Handler,
[13] = 0,
[14] = (uint32_t)&PendSV_Handler,
[15] = (uint32_t)&SysTick_Handler,
[16 ... 79] = (uint32_t)&default_handler
};

View File

@ -0,0 +1,140 @@
/* Falcon-512 KAT extracted from wolfcrypt/test/test.c */
#include <stdint.h>
#define FALCON_KAT_MSG "wolfSSL FN-DSA differential KAT"
#define FALCON512_SIGLEN 654
static const byte FALCON512_pk[] = {
0x09,0x8d,0x15,0xc5,0x31,0x5b,0xa1,0x8a,0x92,0x2d,0x93,0x81,
0x26,0x93,0xa7,0x05,0x1a,0xf2,0x92,0x99,0x0c,0x67,0x77,0x30,
0xdf,0x03,0xb9,0x21,0xbe,0xa1,0x06,0x2e,0x81,0x20,0x6b,0x27,
0x5c,0x7a,0x6d,0x9b,0x1d,0x19,0xb6,0xbc,0x65,0x7c,0xe5,0x02,
0x0a,0xdc,0xa1,0xb9,0x87,0x56,0x6e,0x29,0x0a,0x14,0x85,0x10,
0x80,0xc9,0xc8,0x1b,0x48,0x4c,0x7a,0x28,0x74,0xdc,0x8c,0x38,
0xf8,0x4c,0x8a,0x53,0xe9,0x34,0x03,0x76,0xcc,0x88,0x55,0x2c,
0x48,0x00,0x55,0x3e,0x78,0x0c,0xa4,0xf5,0x3b,0x5d,0xc9,0x77,
0xd9,0xd7,0xec,0xa8,0x28,0xb0,0x4a,0xdb,0xaa,0xa4,0x88,0xcd,
0xde,0xe2,0xc3,0xaf,0xa8,0x15,0x09,0x64,0x9a,0x8f,0x5d,0x37,
0x51,0x26,0xce,0xd3,0x06,0x0c,0x9f,0x35,0x56,0x1f,0x70,0x67,
0x6e,0xf3,0x60,0x90,0x2c,0x54,0x91,0x1c,0xbd,0x3d,0x95,0xa8,
0x54,0x3b,0xc2,0x0e,0x6f,0x90,0x80,0xd7,0xcd,0x03,0x3d,0xa8,
0x05,0x09,0x54,0xab,0xa5,0xec,0x1b,0xe2,0xe7,0x39,0x2c,0x0d,
0xc3,0x53,0xe0,0x34,0xea,0x92,0x1c,0xae,0x2e,0x91,0x68,0x74,
0x82,0xe0,0xdf,0x5d,0x18,0xb8,0xe2,0x47,0xcc,0x84,0x35,0xc4,
0xf7,0x08,0xc7,0x00,0xe8,0xb9,0x64,0x8d,0xe9,0x1b,0xcc,0x2b,
0x28,0x78,0x7a,0x65,0x18,0x67,0x0b,0xb1,0xa9,0x10,0x40,0x8d,
0x1f,0xc5,0x4c,0x64,0xe7,0x99,0xf9,0x0d,0x9f,0xb3,0x71,0x2a,
0xf5,0x2a,0x89,0xd0,0xb2,0xf6,0x80,0x61,0x37,0x50,0x5d,0x16,
0x70,0x82,0x73,0x8e,0x9d,0x59,0x88,0xe9,0x84,0xf7,0x32,0x93,
0xfd,0x24,0x61,0x94,0x2b,0xc6,0xdf,0xf7,0x3b,0x5e,0x05,0x88,
0xc0,0x48,0x2a,0x7c,0x40,0x8a,0x03,0x8f,0x8b,0x3b,0x85,0x7d,
0xe0,0xbb,0x73,0xaf,0xbb,0x4b,0xe9,0xe5,0x76,0x7a,0xd0,0x2c,
0x6a,0xb9,0x60,0x19,0xf7,0xa3,0xc0,0xb0,0x64,0x45,0x71,0xb3,
0x6d,0xdf,0x97,0x59,0x4c,0xc2,0xab,0x0c,0x5b,0x29,0xe1,0x52,
0x21,0x0e,0xcf,0xda,0x4e,0x55,0xc7,0x87,0x39,0x9b,0x0f,0x54,
0x88,0xc4,0xbb,0xe7,0x5b,0xcb,0xb6,0x10,0x80,0x5a,0x16,0x96,
0x8b,0x41,0x9a,0x9a,0x41,0x76,0x88,0x2e,0x02,0xa1,0x83,0x78,
0x19,0x67,0xb2,0x07,0x11,0x55,0x56,0xd3,0x5b,0xea,0x3d,0x19,
0xf9,0x81,0xd8,0xe9,0xa4,0x91,0x94,0x06,0x70,0xb9,0x95,0xbd,
0x7e,0x68,0x05,0x82,0x81,0x8f,0x94,0xab,0x36,0xe8,0xa2,0x4a,
0x02,0x6a,0x33,0x6e,0x00,0x87,0x44,0xe8,0xdc,0xa1,0xee,0xf8,
0x00,0x4d,0xaa,0x81,0x99,0x8e,0x46,0xe8,0x36,0x25,0x0b,0x3e,
0xbe,0xd9,0x03,0x38,0x14,0x62,0x8a,0xb5,0x3e,0x79,0xef,0x69,
0x94,0x41,0x41,0xcf,0x16,0x84,0xa9,0xba,0x0f,0x5a,0xd6,0x48,
0xef,0x57,0x0e,0x76,0xc5,0x89,0xf1,0x71,0x29,0x5f,0xb5,0xe2,
0x09,0x14,0xc3,0xd2,0x3f,0xb1,0xb9,0x41,0xc7,0x91,0xa5,0xda,
0x54,0xb4,0x43,0xba,0xa5,0x50,0xf2,0xa1,0x8d,0x0a,0x59,0x18,
0x1e,0xd1,0x58,0x76,0x1c,0x29,0xfa,0x04,0x8c,0x23,0x66,0xee,
0x8b,0xe1,0x11,0x46,0x0c,0x89,0xe3,0x80,0x56,0xa5,0x70,0xa6,
0x7c,0xf1,0x73,0xf1,0x13,0xe4,0x83,0x25,0xe7,0xea,0xd2,0x8c,
0x39,0x36,0xd6,0x5e,0x4b,0x82,0x5a,0x5e,0xa5,0x0c,0xce,0xaa,
0xb7,0x4e,0x01,0x9b,0x46,0xde,0x81,0xd3,0x2f,0xf7,0xbd,0x60,
0x20,0x77,0xac,0xca,0x62,0x41,0x80,0x1a,0x72,0xe3,0x0d,0x49,
0x74,0x16,0xff,0xe7,0xb0,0x65,0xb3,0xa2,0xda,0x6d,0xe1,0x34,
0x4f,0x0e,0xa7,0xb2,0xdf,0xf2,0x9d,0x6d,0xe3,0x78,0x36,0xe9,
0x43,0x7e,0x0b,0xab,0x0e,0xa8,0xe3,0xf1,0x77,0x27,0x78,0x9d,
0xfd,0x43,0x44,0xdd,0xc8,0x3b,0x1f,0x71,0xc6,0xe5,0xef,0xe2,
0x8c,0x7e,0xc6,0x63,0x8b,0x29,0x24,0x34,0x6a,0xcd,0xd8,0xf4,
0xa8,0x5b,0x7b,0xa6,0x38,0x8f,0x3b,0x59,0x8a,0xff,0xb4,0xbc,
0xd6,0xd5,0x0a,0xc0,0xc3,0x7c,0x40,0x80,0x78,0x31,0x41,0x17,
0x23,0xde,0x28,0xe2,0x79,0x2d,0xeb,0x7b,0xee,0xf6,0x65,0xff,
0xe5,0xf7,0x45,0x86,0x13,0xeb,0xf1,0xc3,0xd8,0x82,0x3c,0xcb,
0x44,0xc9,0xde,0xcc,0x36,0x2d,0x68,0x85,0x64,0x66,0x74,0x81,
0xc0,0x21,0xc2,0xe0,0x53,0xa9,0x05,0xae,0xec,0x05,0x86,0xe6,
0x34,0x88,0xea,0x5e,0x5a,0x6a,0xc2,0xdf,0x51,0x65,0x5c,0x80,
0xc5,0xce,0xe9,0xb8,0x4a,0x88,0x08,0x10,0x56,0xe5,0x29,0xb2,
0x44,0x69,0x73,0x4c,0x4d,0x04,0x21,0xf6,0xc0,0x8b,0xed,0xec,
0x80,0x84,0x08,0xbb,0x6c,0xe0,0xef,0xbb,0xce,0xd8,0x12,0x9a,
0x8d,0x1a,0x54,0x41,0xba,0x63,0xc9,0xa8,0xfe,0x97,0x72,0x2c,
0xe9,0xb7,0xe4,0xa4,0x3e,0xda,0x73,0xa1,0xcc,0x86,0x40,0xb8,
0xae,0x7d,0x91,0x52,0x40,0xe7,0x1b,0x3d,0x0f,0xeb,0x7a,0x4e,
0x0d,0x36,0x0c,0x0d,0xf2,0x00,0xaf,0x08,0x70,0xa5,0x6d,0xa2,
0xf5,0x0b,0xc3,0x51,0x70,0x34,0xc6,0x1d,0x16,0x00,0x5c,0xb6,
0x65,0x71,0x9e,0x8d,0x47,0x35,0x6d,0xae,0xfa,0x6d,0x91,0x05,
0x26,0xfd,0x89,0x45,0x14,0x13,0x90,0x3a,0xd8,0xb4,0x11,0xd1,
0xef,0x57,0x63,0x62,0xea,0xc6,0x6c,0x2c,0xf9,0x0b,0x9c,0xa8,
0xa1,0x01,0x40,0x46,0x87,0x2e,0xe0,0xdb,0x90,0x6f,0x4b,0x10,
0xf2,0x95,0xd1,0x3e,0xdb,0xfd,0x6b,0x0c,0xcc,0x7b,0x73,0x5f,
0x2c,0x98,0x8e,0xb0,0x35,0x7c,0xaa,0x99,0x72,0xf9,0x3d,0x64,
0xc4,0x8f,0x09,0x5f,0xbc,0xeb,0x02,0xb2,0x22,0xff,0x08,0xf8,
0x8a,0xa3,0x0d,0x0e,0xa0,0xb6,0xec,0x89,0x36,0xbf,0x8d,0x8e,
0x0f,0xcd,0x3a,0x76,0xd5,0x19,0xe3,0xa8,0xe6,0x73,0x01,0x47,
0x55,0x05,0x09,0xb5,0x51,0xda,0x10,0x4f,0xd9,
};
static const byte FALCON512_sig[] = {
0x39,0xf9,0x52,0x91,0x34,0x81,0x6f,0x8a,0xd6,0x02,0x62,0x7b,
0x16,0xa3,0x0f,0x19,0xee,0x36,0x30,0x9a,0xe3,0xbd,0x02,0xf7,
0x12,0x4c,0x04,0xb7,0x45,0x2b,0x55,0x65,0xb8,0x7a,0x24,0xca,
0x5b,0xb7,0xde,0xe1,0x86,0x89,0x69,0x90,0xb6,0x12,0x34,0xe2,
0xe2,0x62,0x6d,0x00,0x7a,0x2e,0x75,0x86,0xb6,0x98,0x37,0x69,
0x44,0x58,0xb7,0xab,0xf4,0xa9,0xd6,0x38,0x6f,0x92,0x7e,0x6c,
0x0d,0xcc,0x9c,0x20,0x25,0x45,0x84,0xc5,0x34,0x97,0x94,0xd5,
0xb6,0xa5,0xf4,0x1e,0xac,0x41,0x6b,0xad,0xe4,0x13,0x47,0x01,
0x42,0x86,0xd1,0x50,0xf7,0x09,0x41,0x75,0x69,0x90,0xaf,0xde,
0xd7,0x6b,0xeb,0xd0,0x75,0x77,0x78,0x5a,0xfc,0xb9,0xe3,0xa4,
0x7b,0x6a,0x28,0x67,0x1e,0x56,0xca,0x97,0x71,0x06,0x92,0x1a,
0x5d,0x3e,0x42,0xa7,0x63,0xef,0x2f,0xc6,0x40,0xf1,0x6b,0xb1,
0x1a,0x14,0x2d,0x72,0xac,0x37,0x50,0x05,0xad,0xc1,0xc1,0x74,
0x44,0xc6,0xa7,0xe9,0x62,0x13,0xa2,0x03,0x02,0x67,0x52,0x08,
0x9c,0x9d,0x65,0xb4,0x4b,0x05,0xe4,0xd3,0x43,0x3a,0x91,0x66,
0xf7,0x29,0x13,0x4a,0xfd,0x94,0x8c,0xfa,0x84,0xeb,0xe5,0xd2,
0xd8,0x71,0x91,0x42,0xd9,0xf7,0xae,0x1d,0x88,0x70,0x74,0x33,
0xca,0xae,0xda,0x15,0xc1,0xb7,0xeb,0x11,0x5d,0x39,0x5e,0xc3,
0x76,0x9c,0x3a,0x52,0x1b,0x19,0xe3,0x70,0xdb,0xd2,0x3e,0xe0,
0x47,0x4d,0x74,0x33,0xa5,0xc3,0x5d,0xfc,0x76,0x34,0x2b,0x13,
0x50,0xe6,0x9d,0xb8,0xae,0x44,0x23,0x42,0x95,0x27,0xaf,0x48,
0x9b,0x15,0x11,0x8e,0x13,0xeb,0x36,0xe5,0xe0,0x3d,0xff,0x16,
0x47,0x51,0x20,0xf1,0x4e,0x9a,0x2a,0x22,0x01,0xbd,0xf1,0x40,
0x66,0x74,0xd6,0x52,0x33,0x05,0xb3,0xfe,0xd0,0x5c,0xb7,0x85,
0xc1,0xfb,0x20,0x1e,0x84,0xa2,0x6b,0xcf,0x9b,0xcc,0x8e,0x13,
0x4d,0xa9,0x44,0x92,0x06,0x9c,0x9b,0x3c,0xf3,0x83,0x19,0x58,
0xab,0xe5,0x16,0x4f,0xe2,0x41,0x42,0xd9,0xbc,0xf5,0xa3,0x3b,
0x4e,0x9a,0x5d,0xaf,0x77,0x5d,0xcf,0x9f,0xd2,0x47,0x8c,0x75,
0xb6,0x3d,0x84,0x68,0x36,0xe5,0x15,0x33,0x4c,0xab,0x5a,0x07,
0xa3,0x93,0x6d,0x51,0xc8,0x29,0xc9,0xe1,0xa5,0x57,0x44,0x9a,
0x99,0xab,0x6c,0x5b,0x6e,0xa3,0x26,0xcb,0xea,0xe1,0x0a,0x4a,
0x40,0xb3,0x69,0xbb,0xd6,0xc2,0xcd,0x64,0x35,0x08,0xe9,0x92,
0x61,0x67,0x9f,0x2f,0xc5,0x28,0xc2,0xa0,0x04,0xc9,0xd7,0xf8,
0xd2,0x2b,0x50,0xd6,0x9b,0xf7,0xae,0xf3,0x67,0xd4,0x6a,0x4f,
0x89,0xb4,0x70,0x23,0xe4,0x19,0x97,0x5d,0x86,0xc6,0x2b,0x8f,
0x58,0xd8,0xd6,0x3d,0x59,0x39,0x86,0xa1,0x28,0xc4,0x2b,0xae,
0xf2,0x6d,0x0d,0x76,0x25,0xdc,0x55,0x06,0x73,0x9a,0x27,0xf5,
0x34,0x7f,0xcf,0x9a,0x7a,0xfd,0x1e,0xa5,0xb9,0x66,0x8c,0x9e,
0x78,0x8f,0x9e,0x64,0xcf,0xc8,0xf7,0x73,0x12,0x8a,0x82,0xb3,
0x67,0x03,0xd9,0x1d,0x71,0x63,0x3c,0x5f,0x5e,0x9b,0x2f,0xaf,
0xa1,0x41,0x95,0x47,0x0f,0xff,0x18,0x3e,0xd1,0x09,0x2f,0x23,
0x4e,0x8f,0x4d,0x9b,0xa7,0xe4,0xad,0x47,0xf5,0x17,0xbf,0x86,
0x89,0xd2,0x50,0x6a,0x87,0xdd,0x9e,0xfe,0xf4,0xd0,0xd1,0xa0,
0xcf,0x4f,0x21,0x8c,0x41,0xc5,0xd1,0xa8,0x35,0x9a,0xbe,0xab,
0x95,0x8d,0x5d,0x6d,0x2f,0xbc,0x78,0x8c,0x41,0xee,0xac,0x0c,
0x01,0x48,0x7e,0xd2,0x35,0xba,0x02,0xcc,0x62,0xf9,0xed,0x39,
0x23,0xe2,0x61,0x2d,0xd3,0x61,0x7d,0x43,0x21,0x3a,0x03,0x9c,
0x4b,0x78,0x08,0x2b,0x31,0x5b,0xe8,0xdb,0x4d,0xcb,0xb8,0x8c,
0x54,0xa1,0x58,0xf8,0x2f,0x15,0x64,0x71,0xcc,0x5f,0x41,0x61,
0xd7,0x44,0xb0,0xfb,0x46,0xa8,0xfd,0xe4,0xfc,0xad,0x0c,0x0f,
0xef,0xa8,0x6e,0xb4,0x97,0xfc,0xc2,0x82,0x96,0x40,0x0f,0x1d,
0xd1,0xdf,0x41,0xe0,0x14,0x8f,0x8c,0x22,0x41,0x03,0x5b,0xe6,
0xc8,0x8c,0x71,0xdc,0xf5,0xf6,0xd5,0xa4,0xc3,0x00,0xc3,0x45,
0x1e,0x0f,0x15,0x1d,0xc2,0x70,0x76,0x58,0xf3,0x61,0xa7,0x96,
0x4b,0x58,0x68,0xa4,0x13,0xbf,
};

View File

@ -0,0 +1,189 @@
/* Bare-metal STM32H563 (Cortex-M33) firmware that drives wolfCrypt's native
* Falcon-512 verify path under m33mu, exercising the DSP (SMLAxx / SMUAD +
* packed halfword) NTT/pointwise/norm that auto-enables on __ARM_FEATURE_DSP.
*
* BKPT markers:
* 0x7f: valid signature accepted AND tampered signature rejected (success)
* 0x7c: valid signature was rejected
* 0x7d: tampered signature was accepted
* 0x71: verify returned an operational error
* 0x70: setup/init failure
*/
#include <stdint.h>
#include <string.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/falcon.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include "kat.h"
extern uint32_t _sidata;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
extern void __libc_init_array(void);
#define HEAP_PAINT_WORD 0x48454150u
#define STACK_PAINT_WORD 0x5354414bu
#define STACK_PAINT_BYTES (64u * 1024u)
#define STACK_GUARD_BYTES 512u
static __attribute__((noinline)) void bkpt_success(void)
{ __asm volatile("bkpt #0x7f"); }
static __attribute__((noinline)) void bkpt_valid_rejected(void)
{ __asm volatile("bkpt #0x7c"); }
static __attribute__((noinline)) void bkpt_tamper_accepted(void)
{ __asm volatile("bkpt #0x7d"); }
static __attribute__((noinline)) void bkpt_verify_error(void)
{ __asm volatile("bkpt #0x71"); }
static __attribute__((noinline)) void bkpt_setup_fail(void)
{ __asm volatile("bkpt #0x70"); }
static void spin_forever(void)
{
while (1) {
__asm volatile("wfi");
}
}
static void paint_words(uint32_t* start, uint32_t* end, uint32_t word)
{
while (start < end) {
*start++ = word;
}
}
static void paint_runtime_ram(void)
{
uintptr_t sp_now;
uintptr_t heap_start;
uintptr_t paint_limit;
uintptr_t stack_start;
__asm volatile("mov %0, sp" : "=r"(sp_now));
heap_start = (uintptr_t)&_ebss;
if (sp_now <= (heap_start + STACK_GUARD_BYTES)) {
return;
}
paint_limit = sp_now - STACK_GUARD_BYTES;
paint_words((uint32_t*)heap_start, (uint32_t*)paint_limit, HEAP_PAINT_WORD);
stack_start = paint_limit;
if (stack_start > (heap_start + STACK_PAINT_BYTES)) {
stack_start -= STACK_PAINT_BYTES;
}
else {
stack_start = heap_start;
}
paint_words((uint32_t*)stack_start, (uint32_t*)paint_limit, STACK_PAINT_WORD);
}
/* Some wolfCrypt units reference this even under WC_NO_RNG builds. */
int custom_rand_generate_block(unsigned char* output, unsigned int sz);
int custom_rand_generate_block(unsigned char* output, unsigned int sz)
{
unsigned int i;
for (i = 0; i < sz; ++i) {
output[i] = (unsigned char)(0xa5u ^ (unsigned char)i);
}
return 0;
}
/* Observable state for fault analysis / m33mu symbol dumps. */
volatile int g_init_ret;
volatile int g_import_ret;
volatile int g_verify_ret;
volatile int g_valid_res;
volatile int g_tamper_res;
/* Returns 0 on full success, or a negative marker for the failure kind. */
static int run_falcon_verify(void)
{
falcon_key key;
int res = 0;
int ret;
word32 msgLen = (word32)XSTRLEN(FALCON_KAT_MSG);
static byte sigbuf[FALCON512_SIGLEN];
ret = wc_falcon_init(&key);
if (ret != 0) return -700;
ret = wc_falcon_set_level(&key, 1);
if (ret != 0) { wc_falcon_free(&key); return -700; }
ret = wc_falcon_import_public(FALCON512_pk, (word32)sizeof(FALCON512_pk),
&key);
g_import_ret = ret;
if (ret != 0) { wc_falcon_free(&key); return -700; }
/* 1) A genuine signature must verify (res == 1). */
XMEMCPY(sigbuf, FALCON512_sig, FALCON512_SIGLEN);
res = 0;
ret = wc_falcon_verify_msg(sigbuf, FALCON512_SIGLEN,
(const byte*)FALCON_KAT_MSG, msgLen, &res, &key);
g_verify_ret = ret;
g_valid_res = res;
if (ret != 0) { wc_falcon_free(&key); return -710; }
if (res != 1) { wc_falcon_free(&key); return -720; }
/* 2) Flip a byte in the compressed body; it must NOT verify. */
sigbuf[FALCON512_SIGLEN - 1] ^= 0x01;
res = 1;
(void)wc_falcon_verify_msg(sigbuf, FALCON512_SIGLEN,
(const byte*)FALCON_KAT_MSG, msgLen, &res, &key);
g_tamper_res = res;
wc_falcon_free(&key);
if (res == 1) return -730;
return 0;
}
int main(void)
{
int ret;
paint_runtime_ram();
g_init_ret = wolfCrypt_Init();
if (g_init_ret != 0) {
bkpt_setup_fail();
spin_forever();
}
ret = run_falcon_verify();
if (ret == 0) {
bkpt_success(); /* 0x7f */
}
else if (ret == -720) {
bkpt_valid_rejected(); /* 0x7c */
}
else if (ret == -730) {
bkpt_tamper_accepted(); /* 0x7d */
}
else if (ret == -710) {
bkpt_verify_error(); /* 0x71 */
}
else {
bkpt_setup_fail(); /* 0x70 */
}
spin_forever();
return 0;
}
void Reset_Handler(void);
void Reset_Handler(void)
{
uint32_t* src;
uint32_t* dst;
src = &_sidata;
for (dst = &_sdata; dst < &_edata; ++dst) {
*dst = *src++;
}
for (dst = &_sbss; dst < &_ebss; ++dst) {
*dst = 0;
}
__libc_init_array();
(void)main();
bkpt_setup_fail();
spin_forever();
}

Binary file not shown.

View File

@ -0,0 +1,125 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
extern uint32_t _ebss;
extern uint32_t _estack;
static char* heap_end;
int _write(int file, const char* ptr, int len)
{
(void)file;
(void)ptr;
return len;
}
int _close(int file)
{
(void)file;
return -1;
}
int _fstat(int file, struct stat* st)
{
(void)file;
if (st == 0) {
errno = EINVAL;
return -1;
}
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
(void)file;
return 1;
}
int _lseek(int file, int ptr, int dir)
{
(void)file;
(void)ptr;
(void)dir;
return 0;
}
int _read(int file, char* ptr, int len)
{
(void)file;
(void)ptr;
(void)len;
return 0;
}
void* _sbrk(ptrdiff_t incr)
{
char* prev;
char* next;
if (heap_end == 0) {
heap_end = (char*)&_ebss;
}
prev = heap_end;
next = heap_end + incr;
if (next >= (char*)&_estack) {
errno = ENOMEM;
return (void*)-1;
}
heap_end = next;
return prev;
}
int _gettimeofday(struct timeval* tv, void* tzvp)
{
(void)tzvp;
if (tv == 0) {
errno = EINVAL;
return -1;
}
tv->tv_sec = 0;
tv->tv_usec = 0;
return 0;
}
time_t time(time_t* t)
{
time_t now = 0;
if (t != 0) {
*t = now;
}
return now;
}
void _exit(int status)
{
(void)status;
while (1) {
__asm volatile("wfi");
}
}
int _kill(int pid, int sig)
{
(void)pid;
(void)sig;
errno = EINVAL;
return -1;
}
int _getpid(void)
{
return 1;
}
void _init(void)
{
}
void _fini(void)
{
}

View File

@ -0,0 +1,63 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 0x00200000
RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x000A0000
}
_estack = ORIGIN(RAM) + LENGTH(RAM);
_sidata = LOADADDR(.data);
SECTIONS
{
.isr_vector :
{
KEEP(*(.isr_vector))
} > FLASH
.text :
{
*(.text*)
*(.rodata*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
*(.glue_7)
*(.glue_7t)
*(.eh_frame)
} > FLASH
.preinit_array :
{
__preinit_array_start = .;
KEEP(*(.preinit_array*))
__preinit_array_end = .;
} > FLASH
.init_array :
{
__init_array_start = .;
KEEP(*(.init_array*))
__init_array_end = .;
} > FLASH
.fini_array :
{
__fini_array_start = .;
KEEP(*(.fini_array*))
__fini_array_end = .;
} > FLASH
.data :
{
_sdata = .;
*(.data*)
_edata = .;
} > RAM AT > FLASH
.bss (NOLOAD) :
{
_sbss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > RAM
}

View File

@ -0,0 +1,46 @@
#ifndef WOLFSSL_USER_SETTINGS_H
#define WOLFSSL_USER_SETTINGS_H
#define WOLFSSL_GENERAL_ALIGNMENT 4
#define SINGLE_THREADED
#define WOLFSSL_SMALL_STACK
#define WOLFSSL_USER_IO
#define WOLFSSL_NO_SOCK
#define NO_FILESYSTEM
#define NO_WRITEV
#define NO_MAIN_DRIVER
#define NO_WOLFSSL_DIR
#define WOLFSSL_NO_ASM
#define WC_NO_HARDEN
#define CUSTOM_RAND_GENERATE_BLOCK custom_rand_generate_block
/* Native Falcon, verify-only (no sign/keygen), experimental. The verify path
* needs SHA-3 / SHAKE256 for hash-to-point. The DSP NTT auto-enables on
* Cortex-M33 (__ARM_FEATURE_DSP). */
#define WOLFSSL_EXPERIMENTAL_SETTINGS
#define HAVE_FALCON
#define WOLFSSL_FALCON_VERIFY_ONLY
#define WOLFSSL_SHA3
#define WOLFSSL_SHAKE256
/* Trim everything else. */
#define NO_AES
#define NO_DES3
#define NO_DH
#define NO_DSA
#define NO_ERROR_STRINGS
#define NO_HC128
#define NO_MD4
#define NO_MD5
#define NO_OLD_TLS
#define NO_PSK
#define NO_PWDBASED
#define NO_RABBIT
#define NO_RC4
#define NO_RSA
#define NO_SHA
#define NO_SIG_WRAPPER
int custom_rand_generate_block(unsigned char* output, unsigned int sz);
#endif /* WOLFSSL_USER_SETTINGS_H */

View File

@ -39,10 +39,11 @@
#include <wolfcrypt/src/misc.c>
#endif
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
/* Store a second copy of the public key in key->k immediately after the private
* key, reproducing the historical concat(private,public) layout that
* wc_falcon_check_key compares against. No-op unless both halves are set. */
* wc_falcon_check_key compares against. No-op unless both halves are set.
* Defined unconditionally: wc_falcon_import_public (a verify-only operation)
* calls it. */
static void falcon_store_pub_behind_priv(falcon_key* key)
{
if (!key->pubKeySet || !key->prvKeySet) {
@ -58,6 +59,7 @@ static void falcon_store_pub_behind_priv(falcon_key* key)
}
}
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
/* Generate a new Falcon key pair into key (key->level must be set first).
*
* key [in/out] Falcon key to populate.
@ -144,6 +146,9 @@ int wc_falcon_sign_msg(const byte* in, word32 inLen,
/* No software fallback: only a crypto callback can service the request. */
ret = NO_VALID_DEVID;
#elif defined(WOLFSSL_FALCON_VERIFY_ONLY)
/* inLen/rng are only consumed by the (absent) software or cryptocb paths. */
(void)inLen;
(void)rng;
ret = NOT_COMPILED_IN;
#else
if ((ret == 0) && (!key->prvKeySet)) {

View File

@ -161,6 +161,42 @@ static WC_INLINE word32 falcon_csub(word32 a)
return a;
}
/* Optional ARM DSP acceleration for the verify path (NTT/iNTT/pointwise/norm).
* On cores with the DSP extension (__ARM_FEATURE_DSP: Cortex-M4/M7/M33, ...) the
* butterflies process two packed 16-bit coefficients per iteration using the
* SMLA* 16x16 multiplies, SADD16/SSUB16 packed adds, and a USUB16+SEL packed
* conditional subtract; the squared-norm accumulates two lanes per SMUAD. Every
* result is bit-identical to the scalar Barrett path below. Define
* WOLFSSL_FALCON_NO_NTT_DSP to force the portable C path. */
#if !defined(WOLFSSL_FALCON_NTT_DSP) && defined(__ARM_FEATURE_DSP) && \
!defined(WOLFSSL_FALCON_NO_NTT_DSP)
#define WOLFSSL_FALCON_NTT_DSP
#endif
#ifdef WOLFSSL_FALCON_NTT_DSP
#include <arm_acle.h>
/* q replicated into both halfword lanes. */
#define FALCON_QPK (((word32)FALCON_Q << 16) | (word32)FALCON_Q)
/* Signed 16x16 -> 32 products (coefficients are < q < 2^14, so they fit s16). */
static WC_INLINE word32 falcon_smulbb(word32 a, word32 b) /* a.lo * b.lo */
{ return (word32)__smlabb(a, b, 0); }
static WC_INLINE word32 falcon_smultb(word32 a, word32 b) /* a.hi * b.lo */
{ return (word32)__smlatb(a, b, 0); }
static WC_INLINE word32 falcon_smultt(word32 a, word32 b) /* a.hi * b.hi */
{ return (word32)__smlatt(a, b, 0); }
static WC_INLINE word32 falcon_pack(word32 lo, word32 hi)
{ return (lo & 0xffffu) | (hi << 16); }
/* Two packed halfword lanes, each in [0, 2q) -> [0, q): USUB16 sets APSR.GE per
* lane (set where x >= q), SEL then selects (x - q) on those lanes. */
static WC_INLINE word32 falcon_pcsub(word32 x)
{ word32 d = __usub16(x, FALCON_QPK); return __sel(d, x); }
/* Aliasing-safe packed load/store of a coefficient pair (lowers to LDR/STR). */
static WC_INLINE word32 falcon_ld2(const word16* p)
{ word32 v; XMEMCPY(&v, p, sizeof(v)); return v; }
static WC_INLINE void falcon_st2(word16* p, word32 v)
{ XMEMCPY(p, &v, sizeof(v)); }
#endif /* WOLFSSL_FALCON_NTT_DSP */
/* Forward negacyclic NTT, Cooley-Tukey: natural -> bit-reversed order. */
static void falcon_ntt(word16* a, int n, const word16* zetas)
{
@ -170,6 +206,21 @@ static void falcon_ntt(word16* a, int n, const word16* zetas)
for (i = 0; i < m; i++) {
word32 z = zetas[m + i];
int start = 2 * i * t;
#ifdef WOLFSSL_FALCON_NTT_DSP
if (t >= 2) {
for (j = start; j < start + t; j += 2) {
word32 A = falcon_ld2(a + j); /* [a[j] | a[j+1]] */
word32 B = falcon_ld2(a + j + t); /* [a[j+t] | a[j+1+t]] */
word32 v0 = falcon_barrett(falcon_smulbb(B, z));
word32 v1 = falcon_barrett(falcon_smultb(B, z));
word32 V = falcon_pack(v0, v1);
falcon_st2(a + j, falcon_pcsub(__sadd16(A, V)));
falcon_st2(a + j + t,
falcon_pcsub(__ssub16(__sadd16(A, FALCON_QPK), V)));
}
continue;
}
#endif
for (j = start; j < start + t; j++) {
word32 u = a[j];
word32 v = falcon_barrett((word32)a[j + t] * z);
@ -191,6 +242,22 @@ static void falcon_intt(word16* a, int n, const word16* izetas)
for (i = 0; i < h; i++) {
word32 z = izetas[h + i];
int start = j1;
#ifdef WOLFSSL_FALCON_NTT_DSP
if (t >= 2) {
for (j = start; j < start + t; j += 2) {
word32 A = falcon_ld2(a + j);
word32 B = falcon_ld2(a + j + t);
word32 W = falcon_pcsub(
__ssub16(__sadd16(A, FALCON_QPK), B)); /* csub(u+q-v) */
word32 w0 = falcon_barrett(falcon_smulbb(W, z));
word32 w1 = falcon_barrett(falcon_smultb(W, z));
falcon_st2(a + j, falcon_pcsub(__sadd16(A, B)));
falcon_st2(a + j + t, falcon_pack(w0, w1));
}
j1 += 2 * t;
continue;
}
#endif
for (j = start; j < start + t; j++) {
word32 u = a[j];
word32 v = a[j + t];
@ -684,8 +751,17 @@ int falcon_native_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
falcon_ntt(t, n, zetas);
falcon_ntt(h, n, zetas);
{
int i;
for (i = 0; i < n; i++) {
int i = 0;
#ifdef WOLFSSL_FALCON_NTT_DSP
for (; i + 1 < n; i += 2) {
word32 T = falcon_ld2(t + i);
word32 H = falcon_ld2(h + i);
word32 p0 = falcon_barrett(falcon_smulbb(T, H));
word32 p1 = falcon_barrett(falcon_smultt(T, H));
falcon_st2(t + i, falcon_pack(p0, p1));
}
#endif
for (; i < n; i++) {
t[i] = (word16)falcon_barrett((word32)t[i] * h[i]);
}
}
@ -694,8 +770,23 @@ int falcon_native_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
/* s1 = c - s2*h mod q (centered); accept iff ||(s1,s2)||^2 <= bound. */
{
word64 norm = 0;
int i;
for (i = 0; i < n; i++) {
int i = 0;
#ifdef WOLFSSL_FALCON_NTT_DSP
/* Accumulate two squared coefficients per SMUAD (a.lo^2 + a.hi^2).
* |centered| <= q/2 < 2^13, so each SMUAD result < 2^27 (no overflow);
* the running total is 64-bit. */
for (; i + 1 < n; i += 2) {
word32 d0 = falcon_csub(c[i] + FALCON_Q - t[i]);
word32 d1 = falcon_csub(c[i + 1] + FALCON_Q - t[i + 1]);
word32 s1p = falcon_pack((word32)(sword16)falcon_center(d0),
(word32)(sword16)falcon_center(d1));
word32 s2p = falcon_pack((word32)(sword16)s2[i],
(word32)(sword16)s2[i + 1]);
norm += (word64)(word32)__smuad(s1p, s1p);
norm += (word64)(word32)__smuad(s2p, s2p);
}
#endif
for (; i < n; i++) {
word32 d = falcon_csub(c[i] + FALCON_Q - t[i]);
sword32 s1c = falcon_center(d);
sword32 s2c = s2[i];

View File

@ -37,9 +37,10 @@
#if defined(HAVE_FALCON)
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
#include <wolfssl/wolfcrypt/random.h>
#endif
/* wc_falcon_sign_msg / wc_falcon_make_key are declared with a WC_RNG* even in
* verify-only builds (the sign path then returns NOT_COMPILED_IN), so WC_RNG
* must be visible unconditionally. */
#include <wolfssl/wolfcrypt/random.h>
/* Falcon is the PRE-STANDARDIZATION name for this NIST post-quantum signature
* scheme. NIST is standardizing it as FN-DSA (FIPS 206), which is still a draft.