cmake_minimum_required(VERSION 3.16)
project(TRIKE LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

set(LEVEL 1 CACHE STRING "TRIKE level: 1, 3, or 5")
option(WEAK_KEY_REJECT "Enable paper Algorithm 2" ON)
option(OPTIMIZED_IMPLEMENTATION "Build the optimized AVX-512/VPCLMUL implementation" OFF)
if(NOT LEVEL MATCHES "^(1|3|5)$")
    message(FATAL_ERROR "LEVEL must be 1, 3, or 5")
endif()

find_package(OpenSSL REQUIRED COMPONENTS Crypto)
add_library(trike STATIC
    src/kem.c src/gf2x.c src/decoder.c src/sample.c src/prf.c src/hash.c)
target_include_directories(trike PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_definitions(trike PUBLIC LEVEL=${LEVEL})
target_compile_options(trike PRIVATE -Wall -Wextra -Wpedantic)
target_compile_options(trike PUBLIC
    "$<$<CONFIG:Release>:-O3;-flto>"
    "$<$<AND:$<CONFIG:Release>,$<C_COMPILER_ID:GNU>>:-funroll-all-loops>"
    "$<$<AND:$<CONFIG:Release>,$<C_COMPILER_ID:Clang,AppleClang>>:-funroll-loops>")
target_link_options(trike INTERFACE "$<$<CONFIG:Release>:-flto>")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
    set_property(TARGET trike PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
endif()
target_link_libraries(trike PUBLIC OpenSSL::Crypto)
if(WEAK_KEY_REJECT)
    target_compile_definitions(trike PUBLIC WEAK_KEY_REJECT)
endif()
if(OPTIMIZED_IMPLEMENTATION)
    if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$")
        message(FATAL_ERROR "The optimized implementation requires x86-64 AVX-512/VPCLMUL hardware")
    endif()
    target_compile_definitions(trike PUBLIC OPTIMIZED_IMPLEMENTATION)
    target_compile_options(trike PUBLIC
        -mvpclmulqdq -mavx512f -mavx512bw -mavx512dq -mavx512vl -mavx512vpopcntdq)
endif()

add_executable(kat_kem tests/kat_kem.c src/kem.c)
target_compile_definitions(kat_kem PRIVATE TRIKE_KAT)
target_link_libraries(kat_kem PRIVATE trike)

add_executable(bench_kem tests/bench_kem.c)
target_link_libraries(bench_kem PRIVATE trike)
