# ==============================================================================
# Lore build system
# - normal development targets: test / speed
# - API_PKC submission target: kat_api
# ==============================================================================

CC      := gcc
LDFLAGS :=
CPPFLAGS :=
CFLAGS_BASE := -O3 -Wall -Wextra -Wpedantic -Wmissing-prototypes -Wredundant-decls -Wshadow -Wpointer-arith -fomit-frame-pointer -I.

ARCH := $(shell uname -m)
ifeq ($(filter arm64 aarch64 armv7l armv8l,$(ARCH)),)
LORE_USE_NEON ?= 0
else
LORE_USE_NEON ?= 1
endif
# These SHAKE NEON paths are opt-in: scalar SHAKE is faster on the tested arm64 target.
LORE_USE_NEON_SHAKE ?= 0
LORE_USE_NEON_CORE ?= 0
CFLAGS_NEON :=
ifeq ($(LORE_USE_NEON_SHAKE),1)
CFLAGS_NEON += -DLORE_USE_NEON_SHAKE
endif
ifeq ($(LORE_USE_NEON_CORE),1)
CFLAGS_NEON += -DLORE_USE_NEON_CORE
endif

LEVELS := 2

# Per-level flags
CFLAGS_1 := $(CFLAGS_BASE) $(CFLAGS_NEON) -DLORE_LEVEL=1
CFLAGS_2 := $(CFLAGS_BASE) $(CFLAGS_NEON) -DLORE_LEVEL=2

# API_PKC KAT build:
# force Lore's randombytes() to use drng_algorithm instead of OS entropy
CFLAGS_KAT_1 := $(CFLAGS_1) -DLORE_USE_API_PKC_DRNG
CFLAGS_KAT_2 := $(CFLAGS_2) -DLORE_USE_API_PKC_DRNG

OBJROOT := obj
BINDIR  := .

# Search sources in current dir and test/ dir
VPATH := .:test:simd

# ------------------------------------------------------------------------------
# Source file groups
# ------------------------------------------------------------------------------

# Lore core
SOURCES_BASE := \
	kem.c \
	pke.c \
	indcpa.c \
	polyvec.c \
	poly.c \
	ntt.c \
	sampler.c \
	reduce.c \
	symmetric-shake.c \
	fips202.c \
	toomcook.c \
	verify.c \
	bch_codec.c \
	randombytes.c

ifeq ($(LORE_USE_NEON_SHAKE),1)
SOURCES_BASE += shake_neon.c
endif

# Development executables
SOURCES_TEST_MAIN := test_lore.c
SOURCES_SPEED_MAIN := test_speed.c cpucycles.c speed_print.c

# API_PKC submission KAT
SOURCES_APIKAT := \
	KEM_AlgorithmInstance.c \
	KAT_KEM.c \
	drng.c

# ------------------------------------------------------------------------------
# Derived paths
# ------------------------------------------------------------------------------

BASE_OBJS_1 := $(addprefix $(OBJROOT)/lvl1/,$(SOURCES_BASE:.c=.o))
BASE_OBJS_2 := $(addprefix $(OBJROOT)/lvl2/,$(SOURCES_BASE:.c=.o))

TEST_OBJS_1 := $(addprefix $(OBJROOT)/lvl1/,$(SOURCES_TEST_MAIN:.c=.o))
TEST_OBJS_2 := $(addprefix $(OBJROOT)/lvl2/,$(SOURCES_TEST_MAIN:.c=.o))

SPEED_OBJS_1 := $(addprefix $(OBJROOT)/lvl1/,$(SOURCES_SPEED_MAIN:.c=.o))
SPEED_OBJS_2 := $(addprefix $(OBJROOT)/lvl2/,$(SOURCES_SPEED_MAIN:.c=.o))

KAT_BASE_OBJS_1 := $(addprefix $(OBJROOT)/kat1/,$(SOURCES_BASE:.c=.o))
KAT_BASE_OBJS_2 := $(addprefix $(OBJROOT)/kat2/,$(SOURCES_BASE:.c=.o))

KAT_API_OBJS_1 := $(addprefix $(OBJROOT)/kat1/,$(SOURCES_APIKAT:.c=.o))
KAT_API_OBJS_2 := $(addprefix $(OBJROOT)/kat2/,$(SOURCES_APIKAT:.c=.o))

# ------------------------------------------------------------------------------
# Final targets
# ------------------------------------------------------------------------------

TEST_BINS  := test_lore_1 test_lore_2
SPEED_BINS := test_speed_1 test_speed_2
KAT_BINS   := KAT_KEM_1 KAT_KEM_2

all: kat_api

test: $(TEST_BINS)

speed: $(SPEED_BINS)

kat_api: $(KAT_BINS)

# ------------------------------------------------------------------------------
# Link rules: development
# ------------------------------------------------------------------------------

test_lore_1: $(BASE_OBJS_1) $(TEST_OBJS_1)
	$(CC) $(CFLAGS_1) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

test_lore_2: $(BASE_OBJS_2) $(TEST_OBJS_2)
	$(CC) $(CFLAGS_2) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

test_speed_1: $(BASE_OBJS_1) $(SPEED_OBJS_1)
	$(CC) $(CFLAGS_1) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

test_speed_2: $(BASE_OBJS_2) $(SPEED_OBJS_2)
	$(CC) $(CFLAGS_2) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

# ------------------------------------------------------------------------------
# Link rules: API_PKC KAT
# ------------------------------------------------------------------------------

KAT_KEM_1: $(KAT_BASE_OBJS_1) $(KAT_API_OBJS_1)
	$(CC) $(CFLAGS_KAT_1) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

KAT_KEM_2: $(KAT_BASE_OBJS_2) $(KAT_API_OBJS_2)
	$(CC) $(CFLAGS_KAT_2) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

# ------------------------------------------------------------------------------
# Object directory creation
# ------------------------------------------------------------------------------

$(OBJROOT):
	mkdir -p $(OBJROOT)

$(OBJROOT)/lvl1:
	mkdir -p $@

$(OBJROOT)/lvl2:
	mkdir -p $@

$(OBJROOT)/kat1:
	mkdir -p $@

$(OBJROOT)/kat2:
	mkdir -p $@

# ------------------------------------------------------------------------------
# Compile rules: normal builds
# ------------------------------------------------------------------------------

$(OBJROOT)/lvl1/%.o: %.c | $(OBJROOT) $(OBJROOT)/lvl1
	$(CC) $(CFLAGS_1) $(CPPFLAGS) -c $< -o $@

$(OBJROOT)/lvl2/%.o: %.c | $(OBJROOT) $(OBJROOT)/lvl2
	$(CC) $(CFLAGS_2) $(CPPFLAGS) -c $< -o $@

# ------------------------------------------------------------------------------
# Compile rules: API_PKC KAT builds
# ------------------------------------------------------------------------------

$(OBJROOT)/kat1/%.o: %.c | $(OBJROOT) $(OBJROOT)/kat1
	$(CC) $(CFLAGS_KAT_1) $(CPPFLAGS) -c $< -o $@

$(OBJROOT)/kat2/%.o: %.c | $(OBJROOT) $(OBJROOT)/kat2
	$(CC) $(CFLAGS_KAT_2) $(CPPFLAGS) -c $< -o $@

# ------------------------------------------------------------------------------
# Convenience targets
# ------------------------------------------------------------------------------

run_kat_1: KAT_KEM_1
	./KAT_KEM_1

run_kat_2: KAT_KEM_2
	./KAT_KEM_2

clean:
	rm -rf $(OBJROOT)
	rm -f $(TEST_BINS) $(SPEED_BINS) $(KAT_BINS)
	rm -rf output

.PHONY: all test speed kat_api clean run_kat_1 run_kat_2
